@@ -39,6 +39,9 @@ import { KeypressMode } from '../../../rpc/enums/KeypressMode.js';
3939import { InteractionMode } from '../../../rpc/enums/InteractionMode.js' ;
4040import { PredefinedWindows } from '../../../rpc/enums/PredefinedWindows.js' ;
4141import { SystemCapabilityType } from '../../../rpc/enums/SystemCapabilityType.js' ;
42+ import { _ManagerUtility } from '../../_ManagerUtility.js' ;
43+ import { TextFieldName } from '../../../rpc/enums/TextFieldName.js' ;
44+ import { ImageFieldName } from '../../../rpc/enums/ImageFieldName.js' ;
4245
4346// operations and listeners
4447import { _CheckChoiceVrOptionalInterface } from './_CheckChoiceVrOptionalInterface.js' ;
@@ -301,7 +304,6 @@ class _ChoiceSetManagerBase extends _SubManagerBase {
301304 if ( uniqueChoiceCells . findIndex ( choice => choice . equals ( choices [ index ] ) ) === - 1 ) {
302305 uniqueChoiceCells . push ( choices [ index ] ) ;
303306 }
304-
305307 if ( choiceVoiceCommands !== null ) {
306308 choiceCellWithVoiceCommandCount ++ ;
307309 allVoiceCommandsCount += choiceVoiceCommands . length ;
@@ -505,6 +507,32 @@ class _ChoiceSetManagerBase extends _SubManagerBase {
505507 return modifiedKeyboardConfiguration ;
506508 }
507509
510+ /**
511+ * Finds non-unique choice cells and updates their unique text accordingly
512+ * @param {ChoiceCell[] } strippedCells - Choice cells with their unsupported properties removed
513+ * @param {ChoiceCell[] } unstrippedCells - The original choice cells
514+ */
515+ _addUniqueNamesBasedOnStrippedCells ( strippedCells , unstrippedCells ) {
516+ if ( ! Array . isArray ( strippedCells ) || ! Array . isArray ( unstrippedCells ) || strippedCells . length !== unstrippedCells . length ) {
517+ return ;
518+ }
519+ // array of unique choice cells
520+ const cells = [ ] ;
521+ // array of the count of how many times each cell has been found
522+ const cellsCounter = [ ] ;
523+ strippedCells . forEach ( ( strippedCell , index ) => {
524+ // find if a previous cell was a duplicate and update unique text of the current cell if so
525+ const duplicateIndex = cells . map ( cell => cell . equals ( strippedCell ) ) . indexOf ( true ) ;
526+ if ( duplicateIndex >= 0 ) {
527+ cellsCounter [ duplicateIndex ] ++ ;
528+ unstrippedCells [ index ] . _setUniqueText ( `${ unstrippedCells [ index ] . getText ( ) } (${ cellsCounter [ duplicateIndex ] } )` ) ;
529+ } else {
530+ cells . push ( strippedCell ) ;
531+ cellsCounter . push ( 1 ) ;
532+ }
533+ } ) ;
534+ }
535+
508536
509537 /**
510538 * Return an array of choice cells that have been preloaded to the head unit
@@ -594,20 +622,90 @@ class _ChoiceSetManagerBase extends _SubManagerBase {
594622 . setKeypressMode ( KeypressMode . RESEND_CURRENT_ENTRY ) ;
595623 }
596624
625+ /**
626+ * Clones a list of choice cells
627+ * @param {ChoiceCell[] } originalList - A list of choice cells to be cloned
628+ * @returns {ChoiceCell[]|null } - The cloned cell list
629+ */
630+ _cloneChoiceCellList ( originalList ) {
631+ if ( ! Array . isArray ( originalList ) ) {
632+ return null ;
633+ }
634+ return originalList . map ( ( choiceCell ) => choiceCell . clone ( ) ) ;
635+ }
636+
597637 /**
598638 * Modifies the choices names depending on SDL version
599639 * @param {ChoiceCell[] } choices - The first list of choices
600640 * @returns {ChoiceCell[] } - A deep copy of the name modified choices
601641 */
602642 _getChoicesToBeUploadedWithArray ( choices ) {
643+ const choicesClone = this . _cloneChoiceCellList ( choices ) ;
603644 // If we're running on a connection < RPC 7.1, we need to de-duplicate cells because presenting them will fail if we have the same cell primary text.
604645 if ( choices !== null && this . _lifecycleManager . getSdlMsgVersion ( ) !== null
605646 && ( this . _lifecycleManager . getSdlMsgVersion ( ) . getMajorVersion ( ) < 7
606647 || ( this . _lifecycleManager . getSdlMsgVersion ( ) . getMajorVersion ( ) === 7 && this . _lifecycleManager . getSdlMsgVersion ( ) . getMinorVersion ( ) === 0 ) ) ) {
607648 // version if 7.0.0 or lower
608- this . _addUniqueNamesToCells ( choices ) ;
649+ this . _addUniqueNamesToCells ( choicesClone ) ;
650+ } else {
651+ const strippedCellsClone = this . _removeUnusedProperties ( choicesClone ) ;
652+ this . _addUniqueNamesBasedOnStrippedCells ( strippedCellsClone , choicesClone ) ;
609653 }
610- return choices . map ( choice => choice . clone ( ) ) ; // deep copy
654+
655+ return choicesClone . filter ( ( clonedChoice ) => {
656+ // returns false if the cloned choice appears in the list of preloaded choices
657+ return ! this . _preloadedChoices . map ( ( preloadedChoice ) => {
658+ // the unique text is important for this comparison but it isn't checked by .equals()
659+ return clonedChoice . equals ( preloadedChoice ) && ( clonedChoice . _getUniqueText ( ) === preloadedChoice . _getUniqueText ( ) ) ;
660+ } ) . includes ( true ) ;
661+ } ) ;
662+ }
663+
664+ /**
665+ * Remove properties from ChoiceCells if they are not supported on the head unit
666+ * @param {ChoiceCell[] } choiceCells - The array of ChoiceCells to have its unused properties removed
667+ * @returns {ChoiceCell[] } - An array of ChoiceCells that has had its unsupported properties removed
668+ */
669+ _removeUnusedProperties ( choiceCells ) {
670+ const strippedCellsClone = this . _cloneChoiceCellList ( choiceCells ) ;
671+ for ( const cell of strippedCellsClone ) {
672+ // Strip cell parameters that are not supported on head unit to support uniqueness.
673+ cell . setVoiceCommands ( null ) ;
674+
675+ if ( ! this . _hasTextFieldOfName ( TextFieldName . secondaryText ) ) {
676+ cell . setSecondaryText ( null ) ;
677+ }
678+ if ( ! this . _hasTextFieldOfName ( TextFieldName . tertiaryText ) ) {
679+ cell . setTertiaryText ( null ) ;
680+ }
681+ if ( ! this . _hasImageFieldOfName ( ImageFieldName . choiceImage ) ) {
682+ cell . setArtwork ( null ) ;
683+ }
684+ if ( ! this . _hasImageFieldOfName ( ImageFieldName . choiceSecondaryImage ) ) {
685+ cell . setSecondaryArtwork ( null ) ;
686+ }
687+ }
688+ return strippedCellsClone ;
689+ }
690+
691+ /**
692+ * Check to see if WindowCapability has an ImageFieldName of a given name.
693+ * @private
694+ * @param {ImageFieldName } imageFieldName - Representing a name of a given Image field that would be stored in WindowCapability
695+ * @returns {Boolean } - True if the name exists in WindowCapability, otherwise false
696+ */
697+ _hasImageFieldOfName ( imageFieldName ) {
698+ return this . _defaultMainWindowCapability === null || _ManagerUtility . hasImageFieldOfName ( this . _defaultMainWindowCapability , imageFieldName ) ;
699+ }
700+
701+ /**
702+ * Check to see if WindowCapability has a textField of a given name.
703+ * @private
704+ * @param {TextFieldName } textFieldName - Representing a name of a given text field that would be stored in WindowCapability
705+ * @returns {Boolean } - True if the name exists in WindowCapability, otherwise false
706+ */
707+ _hasTextFieldOfName ( textFieldName ) {
708+ return this . _defaultMainWindowCapability === null || _ManagerUtility . hasTextFieldOfName ( this . _defaultMainWindowCapability , textFieldName ) ;
611709 }
612710
613711 /**
0 commit comments