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 {RecordingPageController} from '../../common/recordingV2/recording_page_controller'; 22import {RECORDING_MODAL_DIALOG_KEY} from '../../common/recordingV2/recording_utils'; 23import {closeModal} from '../../widgets/modal'; 24 25interface RecordingMultipleChoiceAttrs { 26 targetFactories: TargetFactory[]; 27 // Reference to the controller which maintains the state of the recording 28 // page. 29 controller: RecordingPageController; 30} 31 32export class RecordingMultipleChoice 33 implements m.ClassComponent<RecordingMultipleChoiceAttrs> 34{ 35 private selectedIndex: number = -1; 36 37 targetSelection( 38 targets: RecordingTargetV2[], 39 controller: RecordingPageController, 40 ): m.Vnode | undefined { 41 const targetInfo = controller.getTargetInfo(); 42 const targetNames = []; 43 this.selectedIndex = -1; 44 for (let i = 0; i < targets.length; i++) { 45 const targetName = targets[i].getInfo().name; 46 targetNames.push(m('option', targetName)); 47 if (targetInfo && targetName === targetInfo.name) { 48 this.selectedIndex = i; 49 } 50 } 51 52 const selectedIndex = this.selectedIndex; 53 return m( 54 'label', 55 m( 56 'select', 57 { 58 selectedIndex, 59 onchange: (e: Event) => { 60 controller.onTargetSelection((e.target as HTMLSelectElement).value); 61 }, 62 onupdate: (select) => { 63 // Work around mithril bug 64 // (https://github.com/MithrilJS/mithril.js/issues/2107): We 65 // may update the select's options while also changing the 66 // selectedIndex at the same time. The update of selectedIndex 67 // may be applied before the new options are added to the 68 // select element. Because the new selectedIndex may be 69 // outside of the select's options at that time, we have to 70 // reselect the correct index here after any new children were 71 // added. 72 (select.dom as HTMLSelectElement).selectedIndex = 73 this.selectedIndex; 74 }, 75 ...{size: targets.length, multiple: 'multiple'}, 76 }, 77 ...targetNames, 78 ), 79 ); 80 } 81 82 view({attrs}: m.CVnode<RecordingMultipleChoiceAttrs>): m.Vnode[] | undefined { 83 const controller = attrs.controller; 84 if (!controller.shouldShowTargetSelection()) { 85 return undefined; 86 } 87 const targets: RecordingTargetV2[] = []; 88 for (const targetFactory of attrs.targetFactories) { 89 for (const target of targetFactory.listTargets()) { 90 targets.push(target); 91 } 92 } 93 if (targets.length === 0) { 94 return undefined; 95 } 96 97 return [ 98 m('text', 'Select target:'), 99 m( 100 '.record-modal-command', 101 this.targetSelection(targets, controller), 102 m( 103 'button.record-modal-button-high', 104 { 105 disabled: this.selectedIndex === -1, 106 onclick: () => { 107 closeModal(RECORDING_MODAL_DIALOG_KEY); 108 controller.onStartRecordingPressed(); 109 }, 110 }, 111 'Connect', 112 ), 113 ), 114 ]; 115 } 116} 117