1// Copyright (C) 2022 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import m from 'mithril'; 16 17import { 18 RecordingTargetV2, 19 TargetFactory, 20} from '../../common/recordingV2/recording_interfaces_v2'; 21import { 22 RecordingPageController, 23} from '../../common/recordingV2/recording_page_controller'; 24import {fullscreenModalContainer} from '../modal'; 25 26interface RecordingMultipleChoiceAttrs { 27 targetFactories: TargetFactory[]; 28 // Reference to the controller which maintains the state of the recording 29 // page. 30 controller: RecordingPageController; 31} 32 33export class RecordingMultipleChoice implements 34 m.ClassComponent<RecordingMultipleChoiceAttrs> { 35 private selectedIndex: number = -1; 36 37 targetSelection( 38 targets: RecordingTargetV2[], 39 controller: RecordingPageController): m.Vnode|undefined { 40 const targetInfo = controller.getTargetInfo(); 41 const targetNames = []; 42 this.selectedIndex = -1; 43 for (let i = 0; i < targets.length; i++) { 44 const targetName = targets[i].getInfo().name; 45 targetNames.push(m('option', targetName)); 46 if (targetInfo && targetName === targetInfo.name) { 47 this.selectedIndex = i; 48 } 49 } 50 51 const selectedIndex = this.selectedIndex; 52 return m( 53 'label', 54 m('select', 55 { 56 selectedIndex, 57 onchange: (e: Event) => { 58 controller.onTargetSelection( 59 (e.target as HTMLSelectElement).value); 60 }, 61 onupdate: (select) => { 62 // Work around mithril bug 63 // (https://github.com/MithrilJS/mithril.js/issues/2107): We 64 // may update the select's options while also changing the 65 // selectedIndex at the same time. The update of selectedIndex 66 // may be applied before the new options are added to the 67 // select element. Because the new selectedIndex may be 68 // outside of the select's options at that time, we have to 69 // reselect the correct index here after any new children were 70 // added. 71 (select.dom as HTMLSelectElement).selectedIndex = 72 this.selectedIndex; 73 }, 74 ...{size: targets.length, multiple: 'multiple'}, 75 }, 76 ...targetNames), 77 ); 78 } 79 80 view({attrs}: m.CVnode<RecordingMultipleChoiceAttrs>): m.Vnode[]|undefined { 81 const controller = attrs.controller; 82 if (!controller.shouldShowTargetSelection()) { 83 return undefined; 84 } 85 const targets: RecordingTargetV2[] = []; 86 for (const targetFactory of attrs.targetFactories) { 87 for (const target of targetFactory.listTargets()) { 88 targets.push(target); 89 } 90 } 91 if (targets.length === 0) { 92 return undefined; 93 } 94 95 return [ 96 m('text', 'Select target:'), 97 m('.record-modal-command', 98 this.targetSelection(targets, controller), 99 m('button.record-modal-button-high', 100 { 101 disabled: this.selectedIndex === -1, 102 onclick: () => { 103 fullscreenModalContainer.close(); 104 controller.onStartRecordingPressed(); 105 }, 106 }, 107 'Connect')), 108 ]; 109 } 110} 111