Merge "Refactor and simplify layouts and css styles"

This commit is contained in:
Cosmin Băieș
2022-11-03 14:34:09 +00:00
committed by Android (Google) Code Review
41 changed files with 565 additions and 467 deletions

View File

@@ -11,6 +11,7 @@ import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatProgressBarModule } from "@angular/material/progress-bar";
import { FormsModule } from "@angular/forms";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatDividerModule } from "@angular/material/divider";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatIconModule } from "@angular/material/icon";
import { MatInputModule } from "@angular/material/input";
@@ -91,6 +92,7 @@ import { ViewerWindowManagerComponent } from "viewers/viewer_window_manager/view
FormsModule,
MatListModule,
MatCheckboxModule,
MatDividerModule,
MatIconModule,
MatProgressSpinnerModule,
MatProgressBarModule,

View File

@@ -55,7 +55,7 @@ describe("AdbProxyComponent", () => {
it("check correct icon and message displays if no proxy", () => {
component.proxy.setState(ProxyState.NO_PROXY);
fixture.detectChanges();
expect(htmlElement.querySelector(".further-adb-info")?.innerHTML).toContain("Launch the Winscope ADB Connect proxy");
expect(htmlElement.querySelector(".further-adb-info-text")?.innerHTML).toContain("Launch the Winscope ADB Connect proxy");
});
it("check correct icon and message displays if invalid proxy", () => {

View File

@@ -19,45 +19,58 @@ import { proxyClient, ProxyClient, ProxyState } from "trace_collection/proxy_cli
@Component({
selector: "adb-proxy",
template: `
<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 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>
<ng-container [ngSwitch]="proxy.state">
<ng-container *ngSwitchCase="states.NO_PROXY">
<div class="further-adb-info-text">
<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>
<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>
</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 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 class="further-adb-info-actions">
<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>
</ng-container>
<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>
</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 color="primary" mat-stroked-button class="retry" (click)="restart()">Connect</button>
</div>
</div>
<ng-container *ngSwitchCase="states.INVALID_VERSION">
<div class="further-adb-info-text">
<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>
</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>
<div class="further-adb-info-actions">
<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>
</ng-container>
<ng-container *ngSwitchCase="states.UNAUTH">
<div class="further-adb-info-text">
<p class="icon-information mat-body-1">
<mat-icon class="adb-icon">lock</mat-icon>
<span class="adb-info">Proxy authorisation required.</span>
</p>
<p class="mat-body-1">Enter Winscope proxy token:</p>
<mat-form-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>
<div class="further-adb-info-actions">
<button color="primary" mat-stroked-button class="retry" (click)="restart()">Connect</button>
</div>
</ng-container>
<ng-container *ngSwitchDefault></ng-container>
</ng-container>
`,
styles: [
`
@@ -66,14 +79,21 @@ import { proxyClient, ProxyClient, ProxyState } from "trace_collection/proxy_cli
flex-direction: row;
align-items: center;
}
.further-adb-info {
.further-adb-info-text {
display: flex;
flex-direction: column;
overflow-wrap: break-word;
gap: 10px;
margin-bottom: 10px;
}
.further-adb-info p {
margin: 10px 0;
.further-adb-info-actions {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
}
.proxy-key-field {
width: 30rem
.adb-info {
margin-left: 5px;
}
`
]

View File

@@ -18,8 +18,9 @@ import {ComponentFixture, TestBed, ComponentFixtureAutoDetect} from "@angular/co
import { CommonModule } from "@angular/common";
import { MatCardModule } from "@angular/material/card";
import { MatButtonModule } from "@angular/material/button";
import { MatGridListModule } from "@angular/material/grid-list";
import { MatDividerModule } from "@angular/material/divider";
import { MatSliderModule } from "@angular/material/slider";
import { MatSnackBarModule } from "@angular/material/snack-bar";
import { MatToolbarModule } from "@angular/material/toolbar";
import { AppComponent } from "./app.component";
@@ -45,8 +46,9 @@ describe("AppComponent", () => {
CommonModule,
MatCardModule,
MatButtonModule,
MatGridListModule,
MatDividerModule,
MatSliderModule,
MatSnackBarModule,
MatToolbarModule
],
declarations: [
@@ -76,21 +78,24 @@ describe("AppComponent", () => {
});
it("renders the page title", () => {
expect(htmlElement.querySelector("#app-title")?.innerHTML).toContain("Winscope");
expect(htmlElement.querySelector(".app-title")?.innerHTML).toContain("Winscope");
});
it("displays correct elements when no data loaded", async () => {
it("displays correct elements when no data loaded", () => {
component.dataLoaded = false;
fixture.detectChanges();
expect(htmlElement.querySelector(".welcome-info")).toBeTruthy();
expect(htmlElement.querySelector("#viewers")).toBeNull();
expect(htmlElement.querySelector(".collect-traces-card")).toBeTruthy();
expect(htmlElement.querySelector(".upload-traces-card")).toBeTruthy();
expect(htmlElement.querySelector(".viewers")).toBeFalsy();
});
it("displays correct elements when data loaded", async () => {
it("displays correct elements when data loaded", () => {
component.dataLoaded = true;
fixture.detectChanges();
expect(htmlElement.querySelector("#collect-traces-card")).toBeFalsy();
expect(htmlElement.querySelector("#upload-traces-card")).toBeFalsy();
expect(htmlElement.querySelector("#viewers")).toBeTruthy();
expect(htmlElement.querySelector(".welcome-info")).toBeFalsy();
expect(htmlElement.querySelector(".collect-traces-card")).toBeFalsy();
expect(htmlElement.querySelector(".upload-traces-card")).toBeFalsy();
expect(htmlElement.querySelector(".viewers")).toBeTruthy();
});
});

View File

@@ -32,94 +32,96 @@ import { ViewerScreenRecordingComponent } from "viewers/viewer_screen_recording/
@Component({
selector: "app-root",
template: `
<mat-toolbar class="app-toolbar">
<p id="app-title" class="mat-display-1">Winscope</p>
<span class="toolbar-wrapper">
<button *ngIf="dataLoaded" color="primary" mat-stroked-button (click)="toggleTimestamp()">Start/End Timestamp</button>
<button *ngIf="dataLoaded" color="primary" mat-stroked-button (click)="onUploadNewClick()">Upload New</button>
</span>
<mat-toolbar>
<span class="app-title">Winscope</span>
<ng-container *ngIf="dataLoaded">
<button color="primary" mat-stroked-button (click)="toggleTimestamp()">
Start/End Timestamp
</button>
<div class="spacer"></div>
<button color="primary" mat-stroked-button (click)="onUploadNewClick()">
Upload New
</button>
</ng-container>
</mat-toolbar>
<h1 *ngIf="!dataLoaded" class="welcome-info mat-headline">Welcome to Winscope. Please select source to view traces.</h1>
<mat-divider></mat-divider>
<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 id="upload-traces-card" class="homepage-card">
<upload-traces [traceCoordinator]="traceCoordinator" (dataLoadedChange)="onDataLoadedChange($event)"></upload-traces>
</mat-card>
</div>
<ng-container *ngIf="dataLoaded; else noLoadedTracesBlock">
<trace-view
class="viewers"
[viewers]="allViewers"
[store]="store"
(downloadTracesButtonClick)="onDownloadTracesButtonClick()"
></trace-view>
<trace-view
*ngIf="dataLoaded"
id="viewers"
[viewers]="allViewers"
[store]="store"
(downloadTracesButtonClick)="onDownloadTracesButtonClick()"
></trace-view>
<mat-divider></mat-divider>
<div *ngIf="dataLoaded" id="timescrub">
<mat-slider
class="timescrub"
color="primary"
class="time-slider"
step="1"
min="0"
[max]="this.allTimestamps.length-1"
[max]="this.allTimestamps.length - 1"
aria-label="units"
[value]="currentTimestampIndex"
(input)="updateCurrentTimestamp($event)"
></mat-slider>
</div>
<div id="timestamps">
</ng-container>
<ng-template #noLoadedTracesBlock>
<h1 class="welcome-info mat-headline">
Welcome to Winscope. Please select source to view traces.
</h1>
<div class="card-grid">
<collect-traces
class="collect-traces-card homepage-card"
[traceCoordinator]="traceCoordinator"
(dataLoadedChange)="onDataLoadedChange($event)"
[store]="store"
></collect-traces>
<upload-traces
class="upload-traces-card homepage-card"
[traceCoordinator]="traceCoordinator"
(dataLoadedChange)="onDataLoadedChange($event)"
></upload-traces>
</div>
</ng-template>
<div class="timestamps">
</div>
`,
styles: [
`
.app-toolbar {
background-color: white;
border-bottom: 1px solid var(--default-border);
}
#app-title {
margin: 12px 0;
}
.toolbar-wrapper {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.app-title {
margin-right: 10px;
}
.welcome-info {
margin: 16px 0;
margin: 16px 0 6px 0;
text-align: center;
}
.homepage-card {
display: flex;
flex-direction: column;
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 {
.spacer {
flex: 1;
}
.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%
.timescrub {
margin: 8px;
}
`
],

View File

@@ -22,6 +22,7 @@ import { WebAdbComponent } from "./web_adb.component";
import { TraceConfigComponent } from "./trace_config.component";
import { MatListModule } from "@angular/material/list";
import { MatButtonModule } from "@angular/material/button";
import { MatDividerModule } from "@angular/material/divider";
import { MatProgressBarModule } from "@angular/material/progress-bar";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { NO_ERRORS_SCHEMA } from "@angular/core";
@@ -39,6 +40,7 @@ describe("CollectTracesComponent", () => {
MatCardModule,
MatListModule,
MatButtonModule,
MatDividerModule,
MatProgressBarModule,
BrowserAnimationsModule,
MatSnackBarModule
@@ -64,7 +66,7 @@ describe("CollectTracesComponent", () => {
it("renders the expected card title", () => {
fixture.detectChanges();
expect(htmlElement.querySelector("#title")?.innerHTML).toContain("Collect Traces");
expect(htmlElement.querySelector(".title")?.innerHTML).toContain("Collect Traces");
});
it("displays connecting message", () => {
@@ -78,9 +80,9 @@ describe("CollectTracesComponent", () => {
fixture.detectChanges();
fixture.whenStable().then( () => {
expect(htmlElement.querySelector(".set-up-adb")).toBeTruthy();
const proxyTab: HTMLButtonElement | null = htmlElement.querySelector("#proxy-tab");
const proxyTab: HTMLButtonElement | null = htmlElement.querySelector(".proxy-tab");
expect(proxyTab).toBeInstanceOf(HTMLButtonElement);
const webTab: HTMLButtonElement | null = htmlElement.querySelector("#web-tab");
const webTab: HTMLButtonElement | null = htmlElement.querySelector(".web-tab");
expect(webTab).toBeInstanceOf(HTMLButtonElement);
});
});
@@ -110,7 +112,7 @@ describe("CollectTracesComponent", () => {
component.isAdbProxy = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
const webTab: HTMLButtonElement | null = htmlElement.querySelector("#web-tab");
const webTab: HTMLButtonElement | null = htmlElement.querySelector(".web-tab");
expect(webTab).toBeInstanceOf(HTMLButtonElement);
webTab?.dispatchEvent(new Event("click"));
fixture.whenStable().then(() => {
@@ -124,7 +126,7 @@ describe("CollectTracesComponent", () => {
component.connect.devices = jasmine.createSpy().and.returnValue({});
fixture.detectChanges();
fixture.whenStable().then( () => {
const el = htmlElement.querySelector("devices-connecting");
const el = htmlElement.querySelector(".devices-connecting");
expect(el).toBeTruthy();
expect(el?.innerHTML).toContain("No devices detected");
});
@@ -135,7 +137,7 @@ describe("CollectTracesComponent", () => {
component.connect.devices = jasmine.createSpy().and.returnValue({"35562": {model: "Pixel 6", authorised:true}});
fixture.detectChanges();
fixture.whenStable().then( () => {
const el = htmlElement.querySelector("devices-connecting");
const el = htmlElement.querySelector(".devices-connecting");
expect(el).toBeTruthy();
expect(el?.innerHTML).toContain("Connected devices:");
expect(el?.innerHTML).toContain("Pixel 6");
@@ -148,7 +150,7 @@ describe("CollectTracesComponent", () => {
component.connect.devices = jasmine.createSpy().and.returnValue({"35562": {model: "Pixel 6", authorised:false}});
fixture.detectChanges();
fixture.whenStable().then( () => {
const el = htmlElement.querySelector("devices-connecting");
const el = htmlElement.querySelector(".devices-connecting");
expect(el).toBeTruthy();
expect(el?.innerHTML).toContain("Connected devices:");
expect(el?.innerHTML).toContain("unauthorised");
@@ -164,16 +166,16 @@ describe("CollectTracesComponent", () => {
fixture.detectChanges();
fixture.whenStable().then( () => {
const el = htmlElement.querySelector("trace-collection-config");
const el = htmlElement.querySelector(".trace-collection-config");
expect(el).toBeTruthy();
expect(el?.innerHTML).toContain("smartphone");
expect(el?.innerHTML).toContain("Pixel 6");
expect(el?.innerHTML).toContain("35562");
const traceSection = htmlElement.querySelector("trace-section");
const traceSection = htmlElement.querySelector(".trace-section");
expect(traceSection).toBeTruthy();
const dumpSection = htmlElement.querySelector("dump-section");
const dumpSection = htmlElement.querySelector(".dump-section");
expect(dumpSection).toBeTruthy();
});
});

View File

@@ -28,89 +28,132 @@ 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 class="collect-card">
<mat-card-title class="title">Collect Traces</mat-card-title>
<p *ngIf="connect.isConnectingState()" class="connecting-message mat-body-1">Connecting...</p>
<mat-card-content class="collect-card-content">
<p *ngIf="connect.isConnectingState()" class="connecting-message mat-body-1">Connecting...</p>
<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()">
<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()">
<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 color="primary" mat-stroked-button class="start-btn" (click)="startTracing()">Start trace</button>
<div *ngIf="!connect.adbSuccess()" class="set-up-adb">
<button class="proxy-tab" color="primary" mat-stroked-button [ngClass]="tabClass(true)" (click)="displayAdbProxyTab()">ADB Proxy</button>
<!-- <button class="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 class="dump-section">
<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>
<div *ngIf="connect.isDevicesState()" class="devices-connecting">
<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 matListIcon>
{{ connect.devices()[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}
</mat-icon>
<p matLine>
{{ connect.devices()[deviceId].authorised ? connect.devices()[deviceId].model : "unauthorised" }} ({{ deviceId }})
</p>
</mat-list-item>
</mat-list>
</div>
<div *ngIf="connect.isStartTraceState()" class="trace-collection-config">
<mat-list>
<mat-list-item>
<mat-icon matListIcon>smartphone</mat-icon>
<p matLine>
{{ connect.selectedDevice().model }} ({{ connect.selectedDeviceId() }})
<button color="primary" class="change-btn" mat-button (click)="connect.resetLastDevice()">Change device</button>
</p>
</mat-list-item>
</mat-list>
<div class="trace-section">
<trace-config [traces]="setTraces.DYNAMIC_TRACES"></trace-config>
<button color="primary" class="start-btn" mat-stroked-button (click)="startTracing()">Start trace</button>
</div>
<mat-divider></mat-divider>
<div class="dump-section">
<h3 class="mat-subheading-2">Dump targets</h3>
<div class="selection">
<mat-checkbox
*ngFor="let dumpKey of objectKeys(setTraces.DUMPS)"
color="primary"
class="dump-checkbox"
[(ngModel)]="setTraces.DUMPS[dumpKey].run"
>{{setTraces.DUMPS[dumpKey].name}}</mat-checkbox>
</div>
<button color="primary" class="dump-btn" mat-stroked-button (click)="dumpState()">Dump state</button>
</div>
</div>
</div>
<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 *ngIf="connect.isErrorState()" class="unknown-error">
<p class="error-wrapper mat-body-1">
<mat-icon class="error-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 *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 color="primary" class="end-btn" mat-raised-button (click)="endTrace()">End trace</button>
</div>
<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 color="primary" class="end-btn" mat-raised-button (click)="endTrace()">End trace</button>
</div>
<div *ngIf="connect.isLoadDataState()" class="load-data">
<p class="mat-body-1">Loading data...</p>
<mat-progress-bar md-indeterminate></mat-progress-bar>
</div>
<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>
</mat-card>
`,
styles: [
`
.change-btn {
.change-btn, .retry-btn, .edn-btn {
margin-left: 5px;
}
.collect-card {
height: 100%;
display: flex;
flex-direction: column;
overflow: auto;
margin: 10px;
}
.collect-card-content {
overflow: auto;
}
.selection {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
}
.set-up-adb,
.trace-collection-config,
.trace-section,
.dump-section,
.end-tracing,
.load-data,
trace-config {
display: flex;
flex-direction: column;
gap: 10px;
}
.proxy-tab, .web-tab, .start-btn, .dump-btn, .end-btn {
align-self: flex-start;
}
.error-wrapper {
display: flex;
flex-direction: row;
align-items: center;
}
.error-icon {
margin-right: 5px;
}
`
]
})

View File

@@ -22,7 +22,7 @@ import { ParserError, ParserErrorType } from "parsers/parser_factory";
selector: "upload-snack-bar",
template: `
<div class="snack-bar-container">
<p *ngFor="let msg of errorMessages" class="snack-bar-content mat-body-1">{{msg}}</p>
<p *ngFor="let msg of errorMessages" class="mat-body-1">{{msg}}</p>
<button color="primary" mat-button class="snack-bar-action" (click)="snackBarRef.dismiss()">
Close
</button>
@@ -35,9 +35,6 @@ import { ParserError, ParserErrorType } from "parsers/parser_factory";
flex-direction: row;
align-items: center;
}
.snack-bar-content {
color: white;
}
.snack-bar-action {
margin-left: 12px;
}
@@ -61,7 +58,7 @@ export class ParserErrorSnackBarComponent {
if (error.type === ParserErrorType.ALREADY_LOADED && error.traceType) {
errorString = `Cannot load ${error.trace.name}; Already loaded a trace of type ${TRACE_INFO[error.traceType].name}`;
} else if (error.type === ParserErrorType.UNSUPPORTED_FORMAT) {
errorString = `Cannot load ${error.trace.name}; File format is unsupported`;
errorString = `Cannot load ${error.trace.name}; File format is unsupported`;
}
return errorString;
}

View File

@@ -17,6 +17,7 @@ import { CommonModule } from "@angular/common";
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {TraceConfigComponent} from "./trace_config.component";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatDividerModule } from "@angular/material/divider";
import { MatFormFieldModule } from "@angular/material/form-field";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { MatInputModule } from "@angular/material/input";
@@ -33,6 +34,7 @@ describe("TraceConfigComponent", () => {
imports: [
CommonModule,
MatCheckboxModule,
MatDividerModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
@@ -74,7 +76,7 @@ describe("TraceConfigComponent", () => {
it("check that trace checkbox ticked on default run", () => {
component.traces["layers_trace"].run = true;
fixture.detectChanges();
const box = htmlElement.querySelector(".trace-box");
const box = htmlElement.querySelector(".trace-checkbox");
expect(box?.innerHTML).toContain("aria-checked=\"true\"");
expect(box?.innerHTML).toContain("layers_trace");
});
@@ -82,26 +84,34 @@ describe("TraceConfigComponent", () => {
it("check that trace checkbox not ticked on default run", () => {
component.traces["layers_trace"].run = false;
fixture.detectChanges();
const box = htmlElement.querySelector(".trace-box");
const box = htmlElement.querySelector(".trace-checkbox");
expect(box?.innerHTML).toContain("aria-checked=\"false\"");
});
it("check that correct advanced enable config only shows", () => {
it("check that correct advanced enable config shows", () => {
component.traces["layers_trace"].config!.selectionConfigs = [];
fixture.detectChanges();
const adv = htmlElement.querySelector(".config-opt");
expect(adv).toBeTruthy();
expect(adv?.innerHTML).toContain("trace buffers");
expect(adv?.innerHTML).not.toContain("tracing level");
const enable_config_opt = htmlElement.querySelector(".enable-config-opt");
expect(enable_config_opt).toBeTruthy();
expect(enable_config_opt?.innerHTML).toContain("trace buffers");
expect(enable_config_opt?.innerHTML).not.toContain("tracing level");
const selection_config_opt = htmlElement.querySelector(".selection-config-opt");
expect(selection_config_opt).toBeFalsy();
});
it("check that correct advanced selection config shows", () => {
component.traces["layers_trace"].config!.enableConfigs = [];
fixture.detectChanges();
const adv = htmlElement.querySelector(".config-opt");
expect(adv).toBeTruthy();
expect(adv?.innerHTML).not.toContain("trace buffers");
expect(adv?.innerHTML).toContain("tracing level");
const enable_config_opt = htmlElement.querySelector(".enable-config-opt");
expect(enable_config_opt).toBeFalsy();
const selection_config_opt = htmlElement.querySelector(".selection-config-opt");
expect(selection_config_opt).toBeTruthy();
expect(selection_config_opt?.innerHTML).not.toContain("trace buffers");
expect(selection_config_opt?.innerHTML).toContain("tracing level");
});
it("check that changing enable config causes box to change", async () => {
@@ -116,8 +126,7 @@ describe("TraceConfigComponent", () => {
expect(htmlElement.querySelector(".config-selection")?.innerHTML).toContain("value=\"debug\"");
component.traces["layers_trace"].config!.selectionConfigs[0].value = "verbose";
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(htmlElement.querySelector(".config-selection")?.innerHTML).toContain("value=\"verbose\"");
});
await fixture.whenStable();
expect(htmlElement.querySelector(".config-selection")?.innerHTML).toContain("value=\"verbose\"");
});
});

View File

@@ -19,62 +19,65 @@ import { EnableConfiguration, SelectionConfiguration, TraceConfiguration, TraceC
@Component({
selector: "trace-config",
template: `
<div class="card-block">
<h3 class="mat-subheading-2">Trace targets</h3>
<div class="checkboxes">
<h3 class="mat-subheading-2">Trace targets</h3>
<div class="checkboxes">
<mat-checkbox
*ngFor="let traceKey of objectKeys(traces)"
color="primary"
class="trace-checkbox"
[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()">
<mat-divider></mat-divider>
<h3 class="mat-subheading-2">{{traces[traceKey].name}} configuration</h3>
<div *ngIf="traces[traceKey].config?.enableConfigs.length > 0" class="enable-config-opt">
<mat-checkbox
*ngFor="let traceKey of objectKeys(traces)"
*ngFor="let enableConfig of traceEnableConfigs(traces[traceKey])"
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>
class="enable-config"
[disabled]="!traces[traceKey].run && !traces[traceKey].isTraceCollection"
[(ngModel)]="enableConfig.enabled"
(ngModelChange)="changeTraceCollectionConfig(traces[traceKey])"
>{{enableConfig.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?.selectionConfigs.length > 0" class="selection-config-opt">
<mat-form-field
*ngFor="let selectionConfig of traceSelectionConfigs(traces[traceKey])"
class="config-selection"
appearance="fill">
<div *ngIf="traces[traceKey].config?.enableConfigs" class="config-opt">
<mat-checkbox
*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>
<mat-label>{{selectionConfig.name}}</mat-label>
<div *ngIf="traces[traceKey].config?.selectionConfigs" class="config-opt">
<mat-form-field
*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>
</ng-container>
</div>
<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>
</ng-container>
`,
styles: [
`
.card-block {
margin: 15px;
}
.checkboxes {
padding: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 10px;
}
.config-selection {
margin: 0 5px;
.enable-config-opt, .selection-config-opt {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
}
`
]

View File

@@ -17,6 +17,7 @@ import {CommonModule} from "@angular/common";
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from "@angular/core";
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {MatCardModule} from "@angular/material/card";
import {MatDividerModule} from "@angular/material/divider";
import {TraceViewComponent} from "./trace_view.component";
import {ViewerStub} from "viewers/viewer_stub";
@@ -30,7 +31,8 @@ describe("TraceViewComponent", () => {
declarations: [TraceViewComponent],
imports: [
CommonModule,
MatCardModule
MatCardModule,
MatDividerModule
],
schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();

View File

@@ -43,6 +43,7 @@ interface Tab extends View {
(click)="downloadTracesButtonClick.emit()"
>Download all traces</button>
</div>
<mat-divider></mat-divider>
<div class="trace-view-content">
</div>
`,
@@ -59,11 +60,9 @@ interface Tab extends View {
}
.header-items-wrapper {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.tabs-navigation-bar {
@@ -71,12 +70,8 @@ interface Tab extends View {
}
.trace-view-content {
height: 0;
flex-grow: 1;
}
.save-button {
height: 100%;
overflow: auto;
}
`
]

View File

@@ -26,7 +26,10 @@ describe("UploadTracesComponent", () => {
beforeAll(async () => {
await TestBed.configureTestingModule({
imports: [MatCardModule, MatSnackBarModule],
imports: [
MatCardModule,
MatSnackBarModule
],
providers: [MatSnackBar],
declarations: [UploadTracesComponent],
}).compileComponents();

View File

@@ -24,9 +24,10 @@ 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
<mat-card class="upload-card">
<mat-card-title class="title">Upload Traces</mat-card-title>
<mat-card-content
class="drop-box"
ref="drop-box"
(dragleave)="onFileDragOut($event)"
@@ -42,52 +43,78 @@ import { ParserError } from "parsers/parser_factory";
#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>
<mat-icon matListIcon>
{{TRACE_INFO[trace.type].icon}}
</mat-icon>
<p matLine>
{{trace.name}} ({{TRACE_INFO[trace.type].name}})
</p>
<button color="primary" mat-icon-button (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 *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 *ngIf="this.loadedTraces.length === 0" class="drop-info">
<p class="mat-body-1">
Drag your .winscope file(s) or click to upload
</p>
</div>
</mat-card-content>
<div *ngIf="this.loadedTraces.length > 0" class="trace-actions-container">
<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>
</mat-card>
`,
styles: [
`
.drop-box {
height: 400px;
padding: 10px;
.upload-card {
height: 100%;
display: flex;
flex-direction: column;
overflow: auto;
outline: 2px dashed var(--default-border);
outline-offset: -10px;
margin: 10px;
}
.drop-box {
display: flex;
flex-direction: column;
overflow: auto;
border: 2px dashed var(--default-border);
cursor: pointer;
}
.uploaded-files {
height: 100%;
width: 100%;
overflow: auto;
}
.close-btn {
margin-left: auto;
flex: 400px;
padding: 0;
}
.drop-info {
flex: 400px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
pointer-events: none;
margin: auto;
}
.trace-actions-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
}
`
]

View File

@@ -16,7 +16,6 @@
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {WebAdbComponent} from "./web_adb.component";
import { MatIconModule } from "@angular/material/icon";
import { MatCardModule } from "@angular/material/card";
describe("WebAdbComponent", () => {
let fixture: ComponentFixture<WebAdbComponent>;
@@ -25,7 +24,9 @@ describe("WebAdbComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MatIconModule, MatCardModule],
imports: [
MatIconModule
],
declarations: [WebAdbComponent],
}).compileComponents();
fixture = TestBed.createComponent(WebAdbComponent);

View File

@@ -24,7 +24,7 @@ import {Component} from "@angular/core";
</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>
<button color="primary" class="web-select-btn" mat-raised-button>Select a device</button>
`,
styles: [
`
@@ -33,6 +33,9 @@ import {Component} from "@angular/core";
flex-direction: row;
align-items: center;
}
.adb-info, .web-select-btn {
margin-left: 5px;
}
`
]
})

View File

@@ -22,7 +22,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.svg">
</head>
<body>
<body class="mat-app-background">
<app-root></app-root>
</body>
</html>

View File

@@ -31,14 +31,17 @@ $theme: mat.define-light-theme((
color: (
primary: $primary,
accent: $accent,
)
),
density: 0,
));
@include mat.core-theme($theme);
@include mat.button-theme($theme);
@include mat.button-toggle-theme($theme);
@include mat.card-theme($theme);
@include mat.checkbox-theme($theme);
@include mat.divider-theme($theme);
@include mat.form-field-theme($theme);
@include mat.grid-list-theme($theme);
@include mat.icon-theme($theme);
@@ -51,5 +54,5 @@ $theme: mat.define-light-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);
@include mat.tooltip-theme($theme);

View File

@@ -37,22 +37,6 @@ app-root {
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%;
@@ -60,3 +44,7 @@ mat-icon {
flex-direction: row;
overflow: auto;
}
viewer-surface-flinger .properties-view .view-header {
flex: 3;
}

View File

@@ -22,7 +22,7 @@ describe("winscope", () => {
}),
it("has title", () => {
const title = element(by.css("#app-title"));
const title = element(by.css(".app-title"));
expect(title.getText()).toContain("Winscope");
});
});

View File

@@ -21,6 +21,7 @@ import { CommonModule } from "@angular/common";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatDividerModule } from "@angular/material/divider";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { HierarchyTreeBuilder } from "test/unit/hierarchy_tree_builder";
import { TreeComponent } from "viewers/components/tree.component";
@@ -45,9 +46,10 @@ describe("HierarchyComponent", () => {
],
imports: [
CommonModule,
MatCheckboxModule,
MatDividerModule,
MatInputModule,
MatFormFieldModule,
MatCheckboxModule,
BrowserAnimationsModule
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -40,9 +40,8 @@ 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"
color="primary"
[(ngModel)]="userOptions[option].enabled"
(ngModelChange)="updateTree()"
>{{userOptions[option].name}}</mat-checkbox>
@@ -67,24 +66,23 @@ import { TableProperties } from "viewers/common/table_properties";
></tree-node>
</div>
</div>
<mat-divider></mat-divider>
<div class="hierarchy-content">
<div class="tree-wrapper">
<tree-view
*ngIf="tree"
[isFlattened]="isFlattened()"
[isShaded]="true"
[item]="tree"
[dependencies]="dependencies"
[store]="store"
[useGlobalCollapsedState]="true"
[itemsClickable]="true"
[highlightedItems]="highlightedItems"
[pinnedItems]="pinnedItems"
(highlightedItemChange)="highlightedItemChange($event)"
(pinnedItemChange)="pinnedItemChange($event)"
(selectedTreeChange)="selectedTreeChange($event)"
></tree-view>
</div>
<tree-view
*ngIf="tree"
[isFlattened]="isFlattened()"
[isShaded]="true"
[item]="tree"
[dependencies]="dependencies"
[store]="store"
[useGlobalCollapsedState]="true"
[itemsClickable]="true"
[highlightedItems]="highlightedItems"
[pinnedItems]="pinnedItems"
(highlightedItemChange)="highlightedItemChange($event)"
(pinnedItemChange)="pinnedItemChange($event)"
(selectedTreeChange)="selectedTreeChange($event)"
></tree-view>
</div>
`,
styles: [
@@ -92,8 +90,7 @@ import { TableProperties } from "viewers/common/table_properties";
.view-header {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
padding-bottom: 12px;
margin-bottom: 12px;
}
.title-filter {
@@ -107,6 +104,7 @@ import { TableProperties } from "viewers/common/table_properties";
display: flex;
flex-direction: row;
flex-wrap: wrap;
column-gap: 10px;
}
.properties-table {
@@ -114,9 +112,8 @@ import { TableProperties } from "viewers/common/table_properties";
}
.hierarchy-content {
height: 0;
flex-grow: 1;
overflow-y: auto;
height: 100%;
overflow: auto;
}
.pinned-items {
@@ -125,8 +122,8 @@ import { TableProperties } from "viewers/common/table_properties";
border: 2px solid yellow;
}
.tree-wrapper {
overflow-y: auto
tree-view {
overflow: auto;
}
`,
nodeStyles

View File

@@ -15,7 +15,7 @@
*/
import {ComponentFixture, TestBed} from "@angular/core/testing";
import { ImeAdditionalPropertiesComponent } from "./ime_additional_properties.component";
import { MatCardModule } from "@angular/material/card";
import { MatDividerModule } from "@angular/material/divider";
describe("ImeAdditionalPropertiesComponent", () => {
let fixture: ComponentFixture<ImeAdditionalPropertiesComponent>;
@@ -25,7 +25,7 @@ describe("ImeAdditionalPropertiesComponent", () => {
beforeAll(async () => {
await TestBed.configureTestingModule({
imports: [
MatCardModule,
MatDividerModule
],
declarations: [
ImeAdditionalPropertiesComponent

View File

@@ -292,7 +292,7 @@ import { ViewerEvents } from "viewers/common/viewer_events";
}
p.group-header {
color: grey;
color: gray;
}
.left-column {

View File

@@ -20,6 +20,7 @@ import { NO_ERRORS_SCHEMA } from "@angular/core";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatDividerModule } from "@angular/material/divider";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { PropertyGroupsComponent } from "./property_groups.component";
import { TreeComponent } from "./tree.component";
@@ -44,6 +45,7 @@ describe("PropertiesComponent", () => {
MatInputModule,
MatFormFieldModule,
MatCheckboxModule,
MatDividerModule,
BrowserAnimationsModule
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -25,8 +25,10 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
<div class="view-header">
<div class="title-filter">
<h2 class="properties-title mat-title">Properties</h2>
<mat-form-field>
<mat-label>Filter...</mat-label>
<input
matInput
[(ngModel)]="filterString"
@@ -35,24 +37,29 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
/>
</mat-form-field>
</div>
<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>
<property-groups
*ngIf="itemIsSelected() && propertyGroups"
class="property-groups"
[item]="selectedFlickerItem"
></property-groups>
</div>
<mat-divider></mat-divider>
<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
*ngIf="objectKeys(propertiesTree).length > 0"
@@ -67,12 +74,10 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
styles: [
`
.view-header {
flex: 1;
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
padding-bottom: 12px;
overflow-y: auto;
margin-bottom: 12px;
}
.title-filter {
@@ -86,6 +91,7 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
display: flex;
flex-direction: row;
flex-wrap: wrap;
column-gap: 10px;
margin-bottom: 16px;
}
@@ -97,11 +103,12 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
}
.property-groups {
height: 100%;
overflow-y: auto;
}
.tree-wrapper {
overflow-y: auto
overflow: auto
}
`,
],

View File

@@ -16,6 +16,7 @@
import {ComponentFixture, TestBed} from "@angular/core/testing";
import { PropertyGroupsComponent } from "./property_groups.component";
import { ComponentFixtureAutoDetect } from "@angular/core/testing";
import { MatDividerModule } from "@angular/material/divider";
import { TransformMatrixComponent } from "./transform_matrix.component";
describe("PropertyGroupsComponent", () => {
@@ -25,6 +26,9 @@ describe("PropertyGroupsComponent", () => {
beforeAll(async () => {
await TestBed.configureTestingModule({
imports: [
MatDividerModule
],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true }
],

View File

@@ -34,6 +34,7 @@ import { Layer } from "common/trace/flickerlib/common";
</p>
</div>
</div>
<mat-divider></mat-divider>
<div class="group">
<h3 class="group-header mat-subheading-2">Geometry</h3>
<div class="left-column">
@@ -72,6 +73,7 @@ import { Layer } from "common/trace/flickerlib/common";
</p>
</div>
</div>
<mat-divider></mat-divider>
<div class="group">
<h3 class="group-header mat-subheading-2">Buffer</h3>
<div class="left-column">
@@ -112,6 +114,7 @@ import { Layer } from "common/trace/flickerlib/common";
</p>
</div>
</div>
<mat-divider></mat-divider>
<div class="group">
<h3 class="group-header mat-subheading-2">Hierarchy</h3>
<div class="left-column">
@@ -135,6 +138,7 @@ import { Layer } from "common/trace/flickerlib/common";
</p>
</div>
</div>
<mat-divider></mat-divider>
<div class="group">
<h3 class="group-header mat-subheading-2">Effects</h3>
<div class="left-column">
@@ -201,39 +205,42 @@ import { Layer } from "common/trace/flickerlib/common";
</p>
</div>
</div>
<mat-divider></mat-divider>
<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>
<ng-container *ngIf="hasInputChannel()">
<div 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 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>
</ng-container>
<div *ngIf="!hasInputChannel()" class="left-column">
<p class="mat-body-1">
<span class="mat-body-2">Input channel:</span>
@@ -249,12 +256,11 @@ import { Layer } from "common/trace/flickerlib/common";
display: flex;
flex-direction: row;
padding: 8px;
border-bottom: 1px solid var(--default-border);
}
.group-header {
width: 80px;
color: grey;
color: gray;
}
.left-column {
@@ -270,7 +276,7 @@ import { Layer } from "common/trace/flickerlib/common";
}
.column-header {
color: grey;
color: gray;
}
`
],

View File

@@ -304,7 +304,7 @@ export class CanvasGraphics {
const circleMesh = this.makeLabelCircleMesh(rectMesh, rect);
this.scene?.add(circleMesh);
const isGrey = !this.visibleView && !rect.isVisible;
const isGray = !this.visibleView && !rect.isVisible;
let lineEndPos;
const labelYSeparation = 0.5;
@@ -320,14 +320,14 @@ export class CanvasGraphics {
const linePoints = [circleMesh.position, lineEndPos];
const lineGeo = new THREE.BufferGeometry().setFromPoints(linePoints);
const lineMaterial = new THREE.LineBasicMaterial({ color: isGrey ? 0x808080 : 0x000000 });
const lineMaterial = new THREE.LineBasicMaterial({ color: isGray ? 0x808080 : 0x000000 });
const line = new THREE.Line(lineGeo, lineMaterial);
this.scene?.add(line);
this.drawLabelTextHtml(lineEndPos, rect, isGrey);
this.drawLabelTextHtml(lineEndPos, rect, isGray);
}
private drawLabelTextHtml(position: THREE.Vector3, rect: Rectangle, isGrey: boolean) {
private drawLabelTextHtml(position: THREE.Vector3, rect: Rectangle, isGray: boolean) {
// Add rectangle label
const spanText: HTMLElement = document.createElement("span");
spanText.innerText = this.shortenText(rect.label);
@@ -347,8 +347,8 @@ export class CanvasGraphics {
div.appendChild(spanPlaceholder);
div.style.marginTop = "5px";
if (isGrey) {
div.style.color = "grey";
if (isGray) {
div.style.color = "gray";
}
div.style.pointerEvents = "auto";
div.style.cursor = "pointer";
@@ -386,7 +386,7 @@ export class CanvasGraphics {
const blue = ((183 - 44) * darkFactor + 44) / 255;
color = new THREE.Color(red, green, blue);
} else {
// grey (darkness depends on z order)
// gray (darkness depends on z order)
const lower = 120;
const upper = 220;
const darkness = ((upper - lower) * darkFactor + lower) / 255;

View File

@@ -18,7 +18,7 @@ import { Component, ViewChild } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RectsComponent } from "viewers/components/rects/rects.component";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatCardModule } from "@angular/material/card";
import { MatDividerModule } from "@angular/material/divider";
import { MatRadioModule } from "@angular/material/radio";
import { MatSliderModule } from "@angular/material/slider";
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
@@ -34,7 +34,7 @@ describe("RectsComponent", () => {
imports: [
CommonModule,
MatCheckboxModule,
MatCardModule,
MatDividerModule,
MatSliderModule,
MatRadioModule
],

View File

@@ -88,13 +88,19 @@ import { ViewerEvents } from "viewers/common/viewer_events";
</div>
</div>
</div>
<mat-divider></mat-divider>
<div class="rects-content">
<div class="canvas-container">
<canvas class="rects-canvas" (click)="onRectClick($event)" oncontextmenu="return false">
</canvas>
</div>
<div *ngIf="displayIds.length > 1" class="tabs">
<button color="primary" mat-raised-button *ngFor="let displayId of displayIds" (click)="changeDisplayId(displayId)">{{displayId}}</button>
<div *ngIf="displayIds.length > 1" class="display-button-container">
<button
*ngFor="let displayId of displayIds"
color="primary"
mat-raised-button
(click)="changeDisplayId(displayId)"
>{{displayId}}</button>
</div>
</div>
`,
@@ -103,12 +109,12 @@ import { ViewerEvents } from "viewers/common/viewer_events";
.view-controls {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--default-border);
}
.top-view-controls, .slider-view-controls {
display: flex;
flex-direction: row;
flex-wrap: wrap;
column-gap: 10px;
align-items: center;
margin-bottom: 12px;
}
@@ -126,8 +132,10 @@ import { ViewerEvents } from "viewers/common/viewer_events";
top: 0;
}
.rects-content {
height: 0;
flex-grow: 1;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.canvas-container {
height: 100%;
@@ -141,6 +149,12 @@ import { ViewerEvents } from "viewers/common/viewer_events";
.rects-canvas {
cursor: pointer;
}
.display-button-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
column-gap: 10px;
}
`
]
})

View File

@@ -55,7 +55,6 @@ export const treeNodeDataViewStyles = `
export const nodeInnerItemStyles = `
.leaf-node-icon {content: ''; display: inline-block; margin-left: 40%; margin-top: 40%; height: 5px; width: 5px; border-radius: 50%;background-color: #9b9b9b;}
.leaf-node-icon-wrapper, .description, .toggle-tree-btn, .expand-tree-btn, .pin-node-btn { position: relative; display: inline-block;}
mat-icon {margin: 0}
.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;}

View File

@@ -17,8 +17,8 @@ import {ComponentFixture, TestBed} from "@angular/core/testing";
import { ViewerInputMethodComponent } from "./viewer_input_method.component";
import { HierarchyComponent } from "viewers/components/hierarchy.component";
import { PropertiesComponent } from "viewers/components/properties.component";
import { MatDividerModule } from "@angular/material/divider";
import { MatIconModule } from "@angular/material/icon";
import { MatCardModule } from "@angular/material/card";
import { ComponentFixtureAutoDetect } from "@angular/core/testing";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
@@ -34,7 +34,7 @@ describe("ViewerInputMethodComponent", () => {
],
imports: [
MatIconModule,
MatCardModule
MatDividerModule
],
declarations: [
ViewerInputMethodComponent,

View File

@@ -37,12 +37,19 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<ime-additional-properties
*ngIf="inputData?.additionalProperties"
class="ime-additional-properties-view"
[additionalProperties]="inputData?.additionalProperties!"
></ime-additional-properties>
<ng-container *ngIf="inputData?.additionalProperties">
<mat-divider></mat-divider>
<ime-additional-properties
class="ime-additional-properties"
[additionalProperties]="inputData?.additionalProperties!"
></ime-additional-properties>
</ng-container>
</div>
<mat-divider [vertical]="true"></mat-divider>
<properties-view
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
@@ -58,19 +65,12 @@ import { ImeUiData } from "viewers/common/ime_ui_data";
flex-direction: column;
}
.hierarchy-view, .ime-additional-properties-view {
.hierarchy-view, .ime-additional-properties, .properties-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.properties-view {
flex: 1;
padding: 16px;
border-top: 1px solid var(--default-border);
overflow: auto;
}
`,
]

View File

@@ -65,6 +65,7 @@ import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
.drag-icon {
float: left;
margin: 5px 0;
}
.button-minimize {

View File

@@ -15,12 +15,11 @@
*/
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {ViewerSurfaceFlingerComponent} from "./viewer_surface_flinger.component";
import { HierarchyComponent } from "viewers/components/hierarchy.component";
import { PropertiesComponent } from "viewers/components/properties.component";
import { RectsComponent } from "viewers/components/rects/rects.component";
import { MatIconModule } from "@angular/material/icon";
import { MatCardModule } from "@angular/material/card";
import { MatDividerModule } from "@angular/material/divider";
import { ComponentFixtureAutoDetect } from "@angular/core/testing";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
@@ -36,7 +35,7 @@ describe("ViewerSurfaceFlingerComponent", () => {
],
imports: [
MatIconModule,
MatCardModule
MatDividerModule
],
declarations: [
ViewerSurfaceFlingerComponent,
@@ -59,17 +58,17 @@ describe("ViewerSurfaceFlingerComponent", () => {
});
it("creates rects view", () => {
const rectsView = htmlElement.querySelector("#sf-rects-view");
const rectsView = htmlElement.querySelector(".rects-view");
expect(rectsView).toBeTruthy();
});
it("creates hierarchy view", () => {
const hierarchyView = htmlElement.querySelector("#sf-hierarchy-view");
const hierarchyView = htmlElement.querySelector(".hierarchy-view");
expect(hierarchyView).toBeTruthy();
});
it("creates properties view", () => {
const propertiesView = htmlElement.querySelector("#sf-properties-view");
const propertiesView = htmlElement.querySelector(".properties-view");
expect(propertiesView).toBeTruthy();
});
});

View File

@@ -27,7 +27,6 @@ import { PersistentStore } from "common/persistent_store";
template: `
<div class="card-grid">
<rects-view
id="sf-rects-view"
class="rects-view"
[rects]="inputData?.rects ?? []"
[highlightedItems]="inputData?.highlightedItems ?? []"
@@ -35,8 +34,8 @@ import { PersistentStore } from "common/persistent_store";
[forceRefresh]="active"
[hasVirtualDisplays]="inputData?.hasVirtualDisplays ?? false"
></rects-view>
<mat-divider [vertical]="true"></mat-divider>
<hierarchy-view
id="sf-hierarchy-view"
class="hierarchy-view"
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
@@ -45,8 +44,8 @@ import { PersistentStore } from "common/persistent_store";
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<mat-divider [vertical]="true"></mat-divider>
<properties-view
id="sf-properties-view"
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
@@ -58,30 +57,12 @@ import { PersistentStore } from "common/persistent_store";
`,
styles: [
`
.rects-view {
.rects-view, .hierarchy-view, .properties-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.hierarchy-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.properties-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
overflow: auto;
}
`,
]

View File

@@ -16,6 +16,7 @@
import {ScrollingModule} from "@angular/cdk/scrolling";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
import {ComponentFixture, ComponentFixtureAutoDetect, TestBed} from "@angular/core/testing";
import {MatDividerModule} from "@angular/material/divider";
import {UiData, UiDataEntry} from "./ui_data";
import {PropertiesTreeGenerator} from "viewers/common/properties_tree_generator";
import {ViewerTransactionsComponent} from "./viewer_transactions.component";
@@ -31,6 +32,7 @@ describe("ViewerTransactionsComponent", () => {
{ provide: ComponentFixtureAutoDetect, useValue: true }
],
imports: [
MatDividerModule,
ScrollingModule
],
declarations: [

View File

@@ -111,6 +111,8 @@ import {UiData} from "./ui_data";
</cdk-virtual-scroll-viewport>
</div>
<mat-divider [vertical]="true"></mat-divider>
<div class="container-properties">
<h3 class="properties-title mat-title">Properties - Proto Dump</h3>
<tree-view
@@ -127,16 +129,11 @@ import {UiData} from "./ui_data";
display: flex;
flex-direction: column;
padding: 16px;
box-sizing: border-box;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.container-properties {
flex: 1;
padding: 16px;
box-sizing: border-box;
border-top: 1px solid var(--default-border);
}
.entries .filters {

View File

@@ -15,12 +15,11 @@
*/
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {ViewerWindowManagerComponent} from "./viewer_window_manager.component";
import { HierarchyComponent } from "viewers/components/hierarchy.component";
import { PropertiesComponent } from "viewers/components/properties.component";
import { RectsComponent } from "viewers/components/rects/rects.component";
import { MatIconModule } from "@angular/material/icon";
import { MatCardModule } from "@angular/material/card";
import { MatDividerModule } from "@angular/material/divider";
import { ComponentFixtureAutoDetect } from "@angular/core/testing";
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
@@ -36,7 +35,7 @@ describe("ViewerWindowManagerComponent", () => {
],
imports: [
MatIconModule,
MatCardModule
MatDividerModule
],
declarations: [
ViewerWindowManagerComponent,
@@ -59,17 +58,17 @@ describe("ViewerWindowManagerComponent", () => {
});
it("creates rects view", () => {
const rectsView = htmlElement.querySelector("#wm-rects-view");
const rectsView = htmlElement.querySelector(".rects-view");
expect(rectsView).toBeTruthy();
});
it("creates hierarchy view", () => {
const hierarchyView = htmlElement.querySelector("#wm-hierarchy-view");
const hierarchyView = htmlElement.querySelector(".hierarchy-view");
expect(hierarchyView).toBeTruthy();
});
it("creates properties view", () => {
const propertiesView = htmlElement.querySelector("#wm-properties-view");
const propertiesView = htmlElement.querySelector(".properties-view");
expect(propertiesView).toBeTruthy();
});
});

View File

@@ -27,15 +27,14 @@ import { PersistentStore } from "common/persistent_store";
template: `
<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>
<mat-divider [vertical]="true"></mat-divider>
<hierarchy-view
id="wm-hierarchy-view"
class="hierarchy-view"
[tree]="inputData?.tree ?? null"
[dependencies]="inputData?.dependencies ?? []"
@@ -44,8 +43,8 @@ import { PersistentStore } from "common/persistent_store";
[store]="store"
[userOptions]="inputData?.hierarchyUserOptions ?? {}"
></hierarchy-view>
<mat-divider [vertical]="true"></mat-divider>
<properties-view
id="wm-properties-view"
class="properties-view"
[userOptions]="inputData?.propertiesUserOptions ?? {}"
[propertiesTree]="inputData?.propertiesTree ?? {}"
@@ -55,28 +54,12 @@ import { PersistentStore } from "common/persistent_store";
`,
styles: [
`
.rects-view {
.rects-view, .hierarchy-view, .properties-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.hierarchy-view {
flex: 1;
padding: 16px;
display: flex;
flex-direction: column;
border-top: 1px solid var(--default-border);
border-right: 1px solid var(--default-border);
}
.properties-view {
flex: 1;
padding: 16px;
border-top: 1px solid var(--default-border);
overflow: auto;
}
`,
]