You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* eslint-disable lines-around-comment */
  2. // @ts-ignore
  3. import { jitsiLocalStorage } from '@jitsi/js-utils';
  4. import _ from 'lodash';
  5. import { APP_WILL_MOUNT } from '../app/actionTypes';
  6. import PersistenceRegistry from '../redux/PersistenceRegistry';
  7. import ReducerRegistry from '../redux/ReducerRegistry';
  8. import { assignIfDefined } from '../util/helpers';
  9. import { SETTINGS_UPDATED } from './actionTypes';
  10. /**
  11. * The default/initial redux state of the feature {@code base/settings}.
  12. *
  13. * @type Object
  14. */
  15. const DEFAULT_STATE: ISettingsState = {
  16. audioOutputDeviceId: undefined,
  17. avatarURL: undefined,
  18. cameraDeviceId: undefined,
  19. disableCallIntegration: undefined,
  20. disableCrashReporting: undefined,
  21. disableP2P: undefined,
  22. disableSelfView: false,
  23. displayName: undefined,
  24. email: undefined,
  25. localFlipX: true,
  26. maxStageParticipants: 1,
  27. micDeviceId: undefined,
  28. serverURL: undefined,
  29. hideShareAudioHelper: false,
  30. soundsIncomingMessage: true,
  31. soundsParticipantJoined: true,
  32. soundsParticipantKnocking: true,
  33. soundsParticipantLeft: true,
  34. soundsTalkWhileMuted: true,
  35. soundsReactions: true,
  36. startAudioOnly: false,
  37. startWithAudioMuted: false,
  38. startWithVideoMuted: false,
  39. userSelectedAudioOutputDeviceId: undefined,
  40. userSelectedCameraDeviceId: undefined,
  41. userSelectedMicDeviceId: undefined,
  42. userSelectedAudioOutputDeviceLabel: undefined,
  43. userSelectedCameraDeviceLabel: undefined,
  44. userSelectedNotifications: {
  45. 'notify.chatMessages': true
  46. },
  47. userSelectedMicDeviceLabel: undefined,
  48. userSelectedSkipPrejoin: undefined
  49. };
  50. export interface ISettingsState {
  51. audioOutputDeviceId?: string | boolean;
  52. avatarURL?: string;
  53. cameraDeviceId?: string | boolean;
  54. disableCallIntegration?: boolean;
  55. disableCrashReporting?: boolean;
  56. disableP2P?: boolean;
  57. disableSelfView?: boolean;
  58. displayName?: string;
  59. email?: string;
  60. hideShareAudioHelper?: boolean;
  61. localFlipX?: boolean;
  62. maxStageParticipants?: number;
  63. micDeviceId?: string | boolean;
  64. serverURL?: string;
  65. soundsIncomingMessage?: boolean;
  66. soundsParticipantJoined?: boolean;
  67. soundsParticipantKnocking?: boolean;
  68. soundsParticipantLeft?: boolean;
  69. soundsReactions?: boolean;
  70. soundsTalkWhileMuted?: boolean;
  71. startAudioOnly?: boolean;
  72. startWithAudioMuted?: boolean;
  73. startWithVideoMuted?: boolean;
  74. userSelectedAudioOutputDeviceId?: string;
  75. userSelectedAudioOutputDeviceLabel?: string;
  76. userSelectedCameraDeviceId?: string;
  77. userSelectedCameraDeviceLabel?: string;
  78. userSelectedMicDeviceId?: string;
  79. userSelectedMicDeviceLabel?: string;
  80. userSelectedNotifications?: {
  81. [key: string]: boolean;
  82. } | boolean;
  83. userSelectedSkipPrejoin?: boolean;
  84. visible?: boolean;
  85. }
  86. const STORE_NAME = 'features/base/settings';
  87. /**
  88. * Sets up the persistence of the feature {@code base/settings}.
  89. */
  90. const filterSubtree: ISettingsState = {};
  91. // start with the default state
  92. Object.keys(DEFAULT_STATE).forEach(key => {
  93. const key1 = key as keyof typeof filterSubtree;
  94. // @ts-ignore
  95. filterSubtree[key1] = true;
  96. });
  97. // we want to filter these props, to not be stored as they represent
  98. // what is currently opened/used as devices
  99. filterSubtree.audioOutputDeviceId = false;
  100. filterSubtree.cameraDeviceId = false;
  101. filterSubtree.micDeviceId = false;
  102. PersistenceRegistry.register(STORE_NAME, filterSubtree, DEFAULT_STATE);
  103. ReducerRegistry.register<ISettingsState>(STORE_NAME, (state = DEFAULT_STATE, action): ISettingsState => {
  104. switch (action.type) {
  105. case APP_WILL_MOUNT:
  106. return _initSettings(state);
  107. case SETTINGS_UPDATED:
  108. return {
  109. ...state,
  110. ...action.settings
  111. };
  112. }
  113. return state;
  114. });
  115. /**
  116. * Inits the settings object based on what information we have available.
  117. * Info taken into consideration:
  118. * - Old Settings.js style data.
  119. *
  120. * @private
  121. * @param {ISettingsState} featureState - The current state of the feature.
  122. * @returns {Object}
  123. */
  124. function _initSettings(featureState: ISettingsState) {
  125. let settings = featureState;
  126. // Old Settings.js values
  127. // FIXME: jibri uses old settings.js local storage values to set its display
  128. // name and email. Provide another way for jibri to set these values, update
  129. // jibri, and remove the old settings.js values.
  130. const savedDisplayName = jitsiLocalStorage.getItem('displayname');
  131. const savedEmail = jitsiLocalStorage.getItem('email');
  132. // The helper _.escape will convert null to an empty strings. The empty
  133. // string will be saved in settings. On app re-load, because an empty string
  134. // is a defined value, it will override any value found in local storage.
  135. // The workaround is sidestepping _.escape when the value is not set in
  136. // local storage.
  137. const displayName = savedDisplayName === null ? undefined : _.escape(savedDisplayName);
  138. const email = savedEmail === null ? undefined : _.escape(savedEmail);
  139. settings = assignIfDefined({
  140. displayName,
  141. email
  142. }, settings);
  143. return settings;
  144. }