From ae32fd69ceb4349355f7dc900ecffe0723fffb46 Mon Sep 17 00:00:00 2001 From: JaeMan Park Date: Wed, 22 Jul 2026 13:24:26 +0900 Subject: [PATCH] Add button for adding device panel vertically into view panel In the multiple device scanerio with landscape device screen, stacking device panel horizontally is not a good experience to use. (it need to scroll page right side to see the device). Add a toggle button to adding device panel vertically to support this case. b/534778982 --- frontend/go.work.sum | 5 ++++ .../operator/webui/src/app/app.component.html | 8 +++++ .../operator/webui/src/app/app.component.scss | 23 ++++++++++++-- .../operator/webui/src/app/app.component.ts | 2 +- .../webui/src/app/displays.service.ts | 8 ++++- .../app/view-pane/view-pane.component.html | 2 +- .../src/app/view-pane/view-pane.component.ts | 30 ++++++++++++------- 7 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 frontend/go.work.sum diff --git a/frontend/go.work.sum b/frontend/go.work.sum new file mode 100644 index 00000000000..41698fb92ec --- /dev/null +++ b/frontend/go.work.sum @@ -0,0 +1,5 @@ +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= diff --git a/frontend/src/operator/webui/src/app/app.component.html b/frontend/src/operator/webui/src/app/app.component.html index ea094dbb6a2..cb33149281e 100644 --- a/frontend/src/operator/webui/src/app/app.component.html +++ b/frontend/src/operator/webui/src/app/app.component.html @@ -2,6 +2,14 @@

Cloud Android

+ + Add Device Panel
Vertically +
diff --git a/frontend/src/operator/webui/src/app/app.component.scss b/frontend/src/operator/webui/src/app/app.component.scss index 08792390bf2..a8ab6c1f87d 100644 --- a/frontend/src/operator/webui/src/app/app.component.scss +++ b/frontend/src/operator/webui/src/app/app.component.scss @@ -11,14 +11,33 @@ } .cloud-android-toolbar { + display: flex; + justify-content: space-between; + align-items: center; + position: relative; background: #073042; color: #eee; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.5); - text-align: center; } .cloud-android-title { - margin: 0 auto; + position: absolute; + left: 50%; + transform: translateX(-50%); + margin: 0; +} + +.add-vertically-toggle { + margin-left: auto; + font-size: 13px; + line-height: 1.2; + color: #fff; + + ::ng-deep .mdc-label { + color: #fff; + white-space: normal; + text-align: left; + } } .drawer-container { diff --git a/frontend/src/operator/webui/src/app/app.component.ts b/frontend/src/operator/webui/src/app/app.component.ts index a7b54153be5..92b76c2c2ad 100644 --- a/frontend/src/operator/webui/src/app/app.component.ts +++ b/frontend/src/operator/webui/src/app/app.component.ts @@ -13,7 +13,7 @@ import {BUILD_VERSION} from '../environments/version' }) export class AppComponent { readonly version = BUILD_VERSION; - constructor(private displaysService: DisplaysService) {} + constructor(public displaysService: DisplaysService) {} @HostListener('window:message', ['$event']) onWindowMessage(e: MessageEvent) { diff --git a/frontend/src/operator/webui/src/app/displays.service.ts b/frontend/src/operator/webui/src/app/displays.service.ts index f2ebd0e37f8..58b97a3eb07 100644 --- a/frontend/src/operator/webui/src/app/displays.service.ts +++ b/frontend/src/operator/webui/src/app/displays.service.ts @@ -1,5 +1,5 @@ import {Injectable, inject} from '@angular/core'; -import {Subject, merge} from 'rxjs'; +import {BehaviorSubject, Subject, merge} from 'rxjs'; import {map, mergeMap} from 'rxjs/operators'; import {DeviceService} from './device.service'; @@ -9,6 +9,12 @@ import {DeviceService} from './device.service'; export class DisplaysService { private deviceService = inject(DeviceService); + addVertically$ = new BehaviorSubject(false); + + toggleAddVertically(enabled: boolean): void { + this.addVertically$.next(enabled); + } + private devices = this.deviceService.getAllDevices(); private visibleDeviceIds: string[] = []; diff --git a/frontend/src/operator/webui/src/app/view-pane/view-pane.component.html b/frontend/src/operator/webui/src/app/view-pane/view-pane.component.html index 94e7d4002b9..f4672500f49 100644 --- a/frontend/src/operator/webui/src/app/view-pane/view-pane.component.html +++ b/frontend/src/operator/webui/src/app/view-pane/view-pane.component.html @@ -1,7 +1,7 @@
obj.y)) : 0; - const lastRowLayout = layout.filter(obj => obj.y === lastMaxY); - const lastMaxX = - layout.length !== 0 - ? Math.max(...lastRowLayout.map(obj => obj.x)) - : -item.w; - - item.x = lastMaxX + item.w * 2 <= this.cols ? lastMaxX + item.w : 0; - item.y = lastMaxX + item.h * 2 <= this.cols ? lastMaxY : lastMaxY + item.h; + if (this.displaysService.addVertically$.value) { + const newItemY = + layout.length !== 0 + ? Math.max(...layout.map(obj => obj.y + obj.h)) + : 0; + item.x = 0; + item.y = newItemY; + } else { + const lastItemY = + layout.length !== 0 ? Math.max(...layout.map(obj => obj.y)) : 0; + const lastRowLayout = layout.filter(obj => obj.y === lastItemY); + const lastItemX = + layout.length !== 0 + ? Math.max(...lastRowLayout.map(obj => obj.x)) + : -item.w; + + item.x = lastItemX + item.w * (1.0 / this.defaultDisplayZoom) <= this.cols ? lastItemX + item.w : 0; + item.y = lastItemX + item.w * (1.0 / this.defaultDisplayZoom) <= this.cols ? lastItemY : lastItemY + item.h; + } item.placed = true; @@ -294,6 +303,7 @@ export class ViewPaneComponent implements OnInit, OnDestroy, AfterViewInit { } layoutById.set(id, item); }); + return Array.from(layoutById, ([, value]) => value); }, []), map(items => items.filter(item => item.visible)));