Просмотр исходного кода

[RN] Add color scheme support - JS

efficient_tiling
Bettenbuk Zoltan 6 лет назад
Родитель
Сommit
2941f5dde4

+ 14
- 0
react/features/app/components/App.native.js Просмотреть файл

@@ -5,6 +5,7 @@ import { Linking } from 'react-native';
5 5
 
6 6
 import '../../analytics';
7 7
 import '../../authentication';
8
+import { setColorScheme } from '../../base/color-scheme';
8 9
 import { DialogContainer } from '../../base/dialog';
9 10
 import '../../base/jwt';
10 11
 import { Platform } from '../../base/react';
@@ -35,6 +36,11 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
35 36
  */
36 37
 type Props = AbstractAppProps & {
37 38
 
39
+    /**
40
+     * An object of colors that override the default colors of the app/sdk.
41
+     */
42
+    colorScheme: Object,
43
+
38 44
     /**
39 45
      * Whether Picture-in-Picture is enabled. If {@code true}, a toolbar button
40 46
      * is rendered in the {@link Conference} view to afford entering
@@ -56,6 +62,8 @@ type Props = AbstractAppProps & {
56 62
  * @extends AbstractApp
57 63
  */
58 64
 export class App extends AbstractApp {
65
+    _init: Promise<*>;
66
+
59 67
     /**
60 68
      * Initializes a new {@code App} instance.
61 69
      *
@@ -86,6 +94,12 @@ export class App extends AbstractApp {
86 94
     componentDidMount() {
87 95
         super.componentDidMount();
88 96
 
97
+        this._init.then(() => {
98
+            // We set the color scheme early enough so then we avoid any
99
+            // unnecessary re-renders.
100
+            this.state.store.dispatch(setColorScheme(this.props.colorScheme));
101
+        });
102
+
89 103
         Linking.addEventListener('url', this._onLinkingURL);
90 104
     }
91 105
 

+ 160
- 0
react/features/base/color-scheme/ColorSchemeRegistry.js Просмотреть файл

@@ -0,0 +1,160 @@
1
+// @flow
2
+
3
+import { toState } from '../redux';
4
+import { StyleType } from '../styles';
5
+
6
+import defaultScheme from './defaultScheme';
7
+
8
+/**
9
+ * A registry class to register styles that need to be color-schemed.
10
+ *
11
+ * This class uses lazy initialization for scheme-ified style definitions on
12
+ * request.
13
+ */
14
+class ColorSchemeRegistry {
15
+    /**
16
+     * A map of already scheme-ified style definitions.
17
+     */
18
+    _schemedStyles = new Map();
19
+
20
+    /**
21
+     * A map of registered style templates.
22
+     */
23
+    _styleTemplates = new Map();
24
+
25
+    /**
26
+     * Clears the already scheme-ified style definitions. This is useful when
27
+     * the {@code SET_COLOR_SCHEME} action is dispatched (again).
28
+     *
29
+     * @returns {void}
30
+     */
31
+    clear() {
32
+        this._schemedStyles.clear();
33
+    }
34
+
35
+    /**
36
+     * Retreives the color-scheme applied style definition of a component.
37
+     *
38
+     * @param {Object | Function} stateful - An object or function that can be
39
+     * resolved to Redux state using the {@code toState} function.
40
+     * @param {string} componentName - The name of the component whose style we
41
+     * want to retreive.
42
+     * @returns {StyleType}
43
+     */
44
+    get(stateful: Object | Function, componentName: string): StyleType {
45
+        let schemedStyle = this._schemedStyles.get(componentName);
46
+
47
+        if (!schemedStyle) {
48
+            schemedStyle
49
+                = this._applyColorScheme(
50
+                    stateful,
51
+                    componentName,
52
+                    this._styleTemplates.get(componentName));
53
+            this._schemedStyles.set(componentName, schemedStyle);
54
+        }
55
+
56
+        return schemedStyle;
57
+    }
58
+
59
+    /**
60
+     * Registers a style definition to the registry for color-scheming.
61
+     *
62
+     * NOTE: It's suggested to only use this registry on styles where color
63
+     * scheming is needed, otherwise just use a static style object as before.
64
+     *
65
+     * @param {string} componentName - The name of the component to register the
66
+     * style to (e.g. {@code 'Toolbox'}).
67
+     * @param {StyleType} style - The style definition to register.
68
+     * @returns {void}
69
+     */
70
+    register(componentName: string, style: StyleType): void {
71
+        this._styleTemplates.set(componentName, style);
72
+
73
+        // If this is a style overwrite, we need to delete the processed version
74
+        // of the style from the other map
75
+        this._schemedStyles.delete(componentName);
76
+    }
77
+
78
+    /**
79
+     * Creates a color schemed style object applying the color scheme to every
80
+     * colors in the style object prepared in a special way.
81
+     *
82
+     * @param {Object | Function} stateful - An object or function that can be
83
+     * resolved to Redux state using the {@code toState} function.
84
+     * @param {string} componentName - The name of the component to apply the
85
+     * color scheme to.
86
+     * @param {StyleType} style - The style definition to apply the color scheme
87
+     * to.
88
+     * @returns {StyleType}
89
+     */
90
+    _applyColorScheme(
91
+            stateful: Object | Function,
92
+            componentName: string,
93
+            style: StyleType): StyleType {
94
+        let schemedStyle;
95
+
96
+        if (Array.isArray(style)) {
97
+            // The style is an array of styles, we apply the same transformation
98
+            // to each, recursively.
99
+            schemedStyle = [];
100
+
101
+            for (const entry of style) {
102
+                schemedStyle.push(this._applyColorScheme(
103
+                    stateful, componentName, entry));
104
+            }
105
+        } else {
106
+            // The style is an object, we create a copy of it to avoid in-place
107
+            // modification.
108
+            schemedStyle = {
109
+                ...style
110
+            };
111
+
112
+            for (const [
113
+                styleName,
114
+                styleValue
115
+            ] of Object.entries(schemedStyle)) {
116
+                if (typeof styleValue === 'object') {
117
+                    // The value is another style object, we apply the same
118
+                    // transformation recusively.
119
+                    schemedStyle[styleName]
120
+                        = this._applyColorScheme(
121
+                            stateful, componentName, styleValue);
122
+                } else if (typeof styleValue === 'function') {
123
+                    // The value is a function, which indicates that it's a
124
+                    // dynamic, schemed color we need to resolve.
125
+                    schemedStyle[styleName]
126
+                        = this._getColor(stateful, componentName, styleValue());
127
+                }
128
+
129
+            }
130
+        }
131
+
132
+        return schemedStyle;
133
+    }
134
+
135
+    /**
136
+     * Function to get the color value for the provided identifier.
137
+     *
138
+     * @param {Object | Function} stateful - An object or function that can be
139
+     * resolved to Redux state using the {@code toState} function.
140
+     * @param {string} componentName - The name of the component to get the
141
+     * color value for.
142
+     * @param {string} colorDefinition - The string identifier of the color,
143
+     * e.g. {@code appBackground}.
144
+     * @returns {string}
145
+     */
146
+    _getColor(
147
+            stateful: Object | Function,
148
+            componentName: string,
149
+            colorDefinition: string): string {
150
+        const colorScheme = toState(stateful)['features/base/color-scheme'];
151
+
152
+        return {
153
+            ...defaultScheme[componentName],
154
+            ...colorScheme[componentName]
155
+        }[colorDefinition];
156
+    }
157
+
158
+}
159
+
160
+export default new ColorSchemeRegistry();

+ 11
- 0
react/features/base/color-scheme/actionTypes.js Просмотреть файл

@@ -0,0 +1,11 @@
1
+// @flow
2
+
3
+/**
4
+ * Redux action to signal a color scheme change in the app/sdk.
5
+ *
6
+ * {
7
+ *     type: SET_COLOR_SCHEME
8
+ *     colorScheme: Object
9
+ * }
10
+ */
11
+export const SET_COLOR_SCHEME = Symbol('SET_COLOR_SCHEME');

+ 19
- 0
react/features/base/color-scheme/actions.js Просмотреть файл

@@ -0,0 +1,19 @@
1
+// @flow
2
+
3
+import { SET_COLOR_SCHEME } from './actionTypes';
4
+
5
+/**
6
+ * Dispatches a Redux action to set the color scheme of the app/sdk.
7
+ *
8
+ * @param {Object} colorScheme - The color scheme to set.
9
+ * @returns {{
10
+ *     type: SET_COLOR_SCHEME,
11
+ *     colorScheme: Object
12
+ * }}
13
+ */
14
+export function setColorScheme(colorScheme: Object): Object {
15
+    return {
16
+        type: SET_COLOR_SCHEME,
17
+        colorScheme
18
+    };
19
+}

+ 6
- 0
react/features/base/color-scheme/defaultScheme.js Просмотреть файл

@@ -0,0 +1,6 @@
1
+// @flow
2
+
3
+/**
4
+ * The default color scheme of the application.
5
+ */
6
+export default {};

+ 13
- 0
react/features/base/color-scheme/functions.js Просмотреть файл

@@ -0,0 +1,13 @@
1
+// @flow
2
+
3
+/**
4
+ * A special function to be used in the {@code createColorSchemedStyle} call,
5
+ * that denotes that the color is a dynamic color.
6
+ *
7
+ * @param {string} colorDefinition - The definition of the color to mark to be
8
+ * resolved.
9
+ * @returns {Function}
10
+ */
11
+export function schemeColor(colorDefinition: string): Function {
12
+    return () => colorDefinition;
13
+}

+ 8
- 0
react/features/base/color-scheme/index.js Просмотреть файл

@@ -0,0 +1,8 @@
1
+// @flow
2
+
3
+export * from './actions';
4
+export * from './actionTypes';
5
+export * from './functions';
6
+export { default as ColorSchemeRegistry } from './ColorSchemeRegistry';
7
+
8
+import './reducer';

+ 20
- 0
react/features/base/color-scheme/middleware.js Просмотреть файл

@@ -0,0 +1,20 @@
1
+// @flow
2
+
3
+import { MiddlewareRegistry } from '../redux';
4
+
5
+import { SET_COLOR_SCHEME } from './actionTypes';
6
+import ColorSchemeRegistry from './ColorSchemeRegistry';
7
+
8
+/**
9
+ * The middleware of the feature {@code base/color-scheme}.
10
+ *
11
+ * @returns {Function}
12
+ */
13
+MiddlewareRegistry.register((/* store */) => next => action => {
14
+    switch (action.type) {
15
+    case SET_COLOR_SCHEME:
16
+        return ColorSchemeRegistry.clear();
17
+    }
18
+
19
+    return next(action);
20
+});

+ 21
- 0
react/features/base/color-scheme/reducer.js Просмотреть файл

@@ -0,0 +1,21 @@
1
+// @flow
2
+
3
+import _ from 'lodash';
4
+
5
+import { ReducerRegistry } from '../redux';
6
+
7
+import { SET_COLOR_SCHEME } from './actionTypes';
8
+
9
+/**
10
+ * The reducer of the feature {@code base/color-scheme}.
11
+ *
12
+ * @returns {Function}
13
+ */
14
+ReducerRegistry.register('features/base/color-scheme', (state = {}, action) => {
15
+    switch (action.type) {
16
+    case SET_COLOR_SCHEME:
17
+        return _.cloneDeep(action.colorScheme);
18
+    }
19
+
20
+    return state;
21
+});

+ 1
- 1
react/features/base/styles/components/styles/ColorPalette.js Просмотреть файл

@@ -27,7 +27,7 @@ export const ColorPalette = {
27 27
     overflowMenuItemUnderlay: '#EEEEEE',
28 28
     red: '#D00000',
29 29
     transparent: 'rgba(0, 0, 0, 0)',
30
-    white: 'white',
30
+    white: '#FFFFFF',
31 31
 
32 32
     /**
33 33
      * These are colors from the atlaskit to be used on mobile, when needed.

+ 60
- 0
react/features/base/styles/functions.js Просмотреть файл

@@ -6,6 +6,23 @@ import { ColorPalette } from './components';
6 6
 declare type StyleSheet = Object;
7 7
 export type StyleType = StyleSheet | Array<StyleSheet>;
8 8
 
9
+/**
10
+ * RegExp pattern for long HEX color format.
11
+ */
12
+const HEX_LONG_COLOR_FORMAT
13
+    = /^#([0-9A-F]{2,2})([0-9A-F]{2,2})([0-9A-F]{2,2})$/i;
14
+
15
+/**
16
+ * RegExp pattern for short HEX color format.
17
+ */
18
+const HEX_SHORT_COLOR_FORMAT
19
+    = /^#([0-9A-F]{1,1})([0-9A-F]{1,1})([0-9A-F]{1,1})$/i;
20
+
21
+/**
22
+ * RegExp pattern for RGB color format.
23
+ */
24
+const RGB_COLOR_FORMAT = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i;
25
+
9 26
 /**
10 27
  * The list of the well-known style properties which may not be numbers on Web
11 28
  * but must be numbers on React Native.
@@ -87,6 +104,49 @@ export function fixAndroidViewClipping<T: StyleSheet>(styles: T): T {
87 104
     return styles;
88 105
 }
89 106
 
107
+/**
108
+ * Returns an rgba format of the provided color if it's in hex or rgb format.
109
+ *
110
+ * NOTE: The function will return the same color if it's not in one of those
111
+ * two formats (e.g. 'white').
112
+ *
113
+ * @param {string} color - The string representation of the color in rgb or hex
114
+ * format.
115
+ * @param {number} alpha - The alpha value to apply.
116
+ * @returns {string}
117
+ */
118
+export function getRGBAFormat(color: string, alpha: number): string {
119
+    let match = color.match(HEX_LONG_COLOR_FORMAT);
120
+
121
+    if (match) {
122
+        return `#${match[1]}${match[2]}${match[3]}${_getAlphaInHex(alpha)}`;
123
+    }
124
+
125
+    match = color.match(HEX_SHORT_COLOR_FORMAT);
126
+    if (match) {
127
+        return `#${match[1]}${match[1]}${match[2]}${match[2]}${match[3]}${
128
+            match[3]}${_getAlphaInHex(alpha)}`;
129
+    }
130
+
131
+    match = color.match(RGB_COLOR_FORMAT);
132
+    if (match) {
133
+        return `rgba(${match[1]}, ${match[2]}, ${match[3]}, ${alpha})`;
134
+    }
135
+
136
+    return color;
137
+}
138
+
139
+/**
140
+ * Converts an [0..1] alpha value into HEX.
141
+ *
142
+ * @param {number} alpha - The alpha value to convert.
143
+ * @returns {string}
144
+ */
145
+function _getAlphaInHex(alpha: number): string {
146
+    return Number(Math.round(255 * alpha)).toString(16)
147
+        .padStart(2, '0');
148
+}
149
+
90 150
 /**
91 151
  * Shims style properties to work correctly on native. Allows us to minimize the
92 152
  * number of style declarations that need to be set or overridden for specific

Загрузка…
Отмена
Сохранить