Browse Source

- Dark mode support
- Code refactoring

Alex Trofimov 6 years ago
parent
commit
3a1de8d78c
5 changed files with 265 additions and 153 deletions
  1. 200 152
      App.js
  2. 6 0
      ios/Podfile.lock
  3. 3 0
      ios/una/Info.plist
  4. 55 1
      package-lock.json
  5. 1 0
      package.json

+ 200 - 152
App.js

@@ -27,6 +27,7 @@ import {
     Drawer,
     Drawer,
 } from 'native-base';
 } from 'native-base';
 
 
+import { initialMode, useDarkMode, DynamicStyleSheet, DynamicValue, useDynamicStyleSheet, eventEmitter } from 'react-native-dark-mode';
 import JitsiMeet, { JitsiMeetView } from 'react-native-jitsi-meet';
 import JitsiMeet, { JitsiMeetView } from 'react-native-jitsi-meet';
 import VideoCall from './VideoCall';
 import VideoCall from './VideoCall';
 
 
@@ -35,6 +36,8 @@ import { version } from './package.json';
 type Props = {};
 type Props = {};
 
 
 const BASE_URL = 'https://una.io/';
 const BASE_URL = 'https://una.io/';
+const MIX_LIGHT = '12';
+const MIX_DARK = '13';
 const TEMPLATE = 'protean';
 const TEMPLATE = 'protean';
 const TITLE = 'UNA.IO';
 const TITLE = 'UNA.IO';
 const ONESIGNALAPPID = '';
 const ONESIGNALAPPID = '';
@@ -43,12 +46,13 @@ export default class App extends Component<Props> {
 
 
     loading = false;
     loading = false;
     videoCallAudio = false;
     videoCallAudio = false;
+    mode = initialMode;
 
 
     constructor(props) {
     constructor(props) {
         super(props);
         super(props);
 
 
         this.state = {
         this.state = {
-            url: `${BASE_URL}?skin=${TEMPLATE}`,
+            url: `${BASE_URL}?skin=${TEMPLATE}&mix=${'dark' == this.mode ? MIX_DARK : MIX_LIGHT}`,
             status: 'No Page Loaded',
             status: 'No Page Loaded',
             backButtonEnabled: false,
             backButtonEnabled: false,
             forwardButtonEnabled: false,
             forwardButtonEnabled: false,
@@ -68,6 +72,15 @@ export default class App extends Component<Props> {
         this.onConferenceWillJoin = this.onConferenceWillJoin.bind(this);
         this.onConferenceWillJoin = this.onConferenceWillJoin.bind(this);
 
 
         this.onVideoCallStart = this.onVideoCallStart.bind(this);
         this.onVideoCallStart = this.onVideoCallStart.bind(this);
+
+        eventEmitter.on('currentModeChanged', this.onModeChanged.bind(this));
+    }
+
+    onModeChanged(newMode) {
+        this.mode = newMode;
+        this.setState ({
+            key: this.state.key + 1,
+        });
     }
     }
 
 
     onConferenceTerminated(e) {
     onConferenceTerminated(e) {
@@ -168,12 +181,11 @@ export default class App extends Component<Props> {
     
     
     onHomeMenu() {
     onHomeMenu() {
         this.endVideoCall();
         this.endVideoCall();
-
-        if (`${BASE_URL}?skin=${TEMPLATE}` == this.state.url || `${BASE_URL}` == this.state.url || `${BASE_URL}index.php` == this.state.url) {
+        if (`${BASE_URL}` == this.state.url || this.state.url.startsWith(`${BASE_URL}?skin=${TEMPLATE}`) || `${BASE_URL}index.php` == this.state.url) {
             this.injectJavaScript("bx_mobile_apps_close_sliding_menus()");
             this.injectJavaScript("bx_mobile_apps_close_sliding_menus()");
         } else {
         } else {
             this.setState ({
             this.setState ({
-                url: `${BASE_URL}?skin=${TEMPLATE}`,
+                url: `${BASE_URL}?skin=${TEMPLATE}&mix=${'dark' == this.mode ? MIX_DARK : MIX_LIGHT}`,
                 searchbar: false,
                 searchbar: false,
                 key: this.state.key + 1,
                 key: this.state.key + 1,
             });
             });
@@ -408,12 +420,7 @@ export default class App extends Component<Props> {
     }
     }
     
     
     render() {
     render() {
-        StatusBar.setBarStyle(Platform.OS === 'android' ? 'light-content' : 'dark-content', false);
-        return (
-            <Container>
-            <Drawer ref="drawer" content={this.renderDrawer()} onClose={this.drawerClose.bind(this)}>
-                {this.state.searchbar ? this.renderToolbarSearch() : this.renderToolbar() }
-                {this.state.videoCall && this.state.videoCallUri ? this.renderVideoCall() : (<View />)}
+        var sWebview = (
                 <WebView
                 <WebView
                     useWebKit={true}
                     useWebKit={true}
 
 
@@ -427,173 +434,214 @@ export default class App extends Component<Props> {
                     hideKeyboardAccessoryView={true}
                     hideKeyboardAccessoryView={true}
                     injectedJavaScript={this.javascriptToInject()}
                     injectedJavaScript={this.javascriptToInject()}
                     onShouldStartLoadWithRequest={this.onWebViewShouldStartLoadWithRequest.bind(this)}
                     onShouldStartLoadWithRequest={this.onWebViewShouldStartLoadWithRequest.bind(this)}
-
                     onNavigationStateChange={this.onWebViewNavigationStateChange.bind(this)}
                     onNavigationStateChange={this.onWebViewNavigationStateChange.bind(this)}
-                    style={styles.containerWebView}
-                    source={{uri: `${BASE_URL}?skin=${TEMPLATE}`}}
+                    style={{flex: 1}}
+                    source={{uri: `${BASE_URL}?skin=${TEMPLATE}&mix=${'dark' == this.mode ? MIX_DARK : MIX_LIGHT}`}}
                     userAgent={"UNAMobileApp/Mobile (" + Platform.OS + ")"}
                     userAgent={"UNAMobileApp/Mobile (" + Platform.OS + ")"}
                     onMessage={this.onWebViewMessage.bind(this)}
                     onMessage={this.onWebViewMessage.bind(this)}
                     allowFileAccess={true}
                     allowFileAccess={true}
                     onLoad={this.onWebViewLoadEnd.bind(this)}
                     onLoad={this.onWebViewLoadEnd.bind(this)}
                     onLoadStart={this.onWebViewLoadStart.bind(this)}
                     onLoadStart={this.onWebViewLoadStart.bind(this)}
                 />
                 />
-                {this.state.data.loggedin && (
-                    <Footer>
-                        <FooterTab>
-                            <Button vertical onPress={this.onMainMenu.bind(this)}>
-                                <Icon name="bars" type="FontAwesome5" />
-                            </Button>
-                        </FooterTab>
-                        <FooterTab>
-                            <Button vertical onPress={this.onNotificationsMenu.bind(this)} badge={this.state.data.bubbles['notifications-notifications'] > 0 ? true : false}>
-                                {this.state.data.bubbles['notifications-notifications'] > 0 && 
-                                    (<Badge><Text>{this.state.data.bubbles['notifications-notifications']}</Text></Badge>)
-                                }
-                                <Icon name="bell" type="FontAwesome5" solid />
-                            </Button>
-                        </FooterTab>
-{/*
-                        <FooterTab>
-                            <Button vertical onPress={this.onVideoCallToggle.bind(this)}>
-                                <Icon name="video" type="FontAwesome5" solid />
-                            </Button>
-                        </FooterTab>
-*/}
-                        <FooterTab>
-                            <Button vertical onPress={this.onAddMenu.bind(this)}>
-                                <Icon name="plus-circle" type="FontAwesome5" solid />
-                            </Button>
-                        </FooterTab>
-                        <FooterTab>
-                            <Button vertical onPress={this.onMessengerMenu.bind(this)} badge={this.state.data.bubbles['notifications-messenger'] > 0 ? true : false}>
-                                {this.state.data.bubbles['notifications-messenger'] > 0 && 
-                                    (<Badge><Text>{this.state.data.bubbles['notifications-messenger']}</Text></Badge>)
-                                }
-                                <Icon name="comments" type="FontAwesome5" solid />
-                            </Button>
-                        </FooterTab>                    
-                        <FooterTab>
-                            <Button vertical onPress={this.onProfileMenu.bind(this)} badge={this.state.data.bubbles_num > 0 ? true : false}>
-                                {this.state.data.bubbles_num > 0 && 
-                                    (<Badge><Text>{this.state.data.bubbles_num}</Text></Badge>)
-                                }
-                                <Icon name="user" type="FontAwesome5" solid />
-                            </Button>
-                        </FooterTab>
-                    </Footer>
-                )}
-                {this.state.loading && (
-                    <View style={styles.viewLoading2}>
-                        <ActivityIndicator size="large" color="#fff" />
-                    </View>
-                )}
+        );
+        return (
+            <Container>
+            <Drawer ref="drawer" content={<UnaDrawer onLogin={this.onDrawerLoginMenu.bind(this)} onJoin={this.onDrawerJoinMenu.bind(this)} onForotPassword={this.onDrawerForgotMenu.bind(this)} onClose={this.drawerClose.bind(this)} />} onClose={this.drawerClose.bind(this)}>
+            <UnaApp 
+                webview={sWebview}
+                state={this.state}
+                videoCallAudio={this.videoCallAudio}
+                onSearch={this.onSearch.bind(this)}
+                onSearchCancelMenu={this.onSearchCancelMenu.bind(this)}
+                onMainMenu={this.onMainMenu.bind(this)}
+                onHomeMenu={this.onHomeMenu.bind(this)}
+                onAddMenu={this.onAddMenu.bind(this)}
+                onSearchMenu={this.onSearchMenu.bind(this)}
+                onNotificationsMenu={this.onNotificationsMenu.bind(this)}
+                onMessengerMenu={this.onMessengerMenu.bind(this)}
+                onProfileMenu={this.onProfileMenu.bind(this)}
+                onVideoCallToggle={this.onVideoCallToggle.bind(this)}
+                onConferenceTerminated={this.onConferenceTerminated}
+                onConferenceJoined={this.onConferenceJoined}
+                onConferenceWillJoin={this.onConferenceWillJoin} />
             </Drawer>
             </Drawer>
             </Container>
             </Container>
         );
         );
     }
     }
+}
 
 
-    renderVideoCall () {
-        return (
-            <View style={styles.containerVideoCall}>
-                <VideoCall onConferenceTerminated={this.onConferenceTerminated} onConferenceJoined={this.onConferenceJoined} onConferenceWillJoin={this.onConferenceWillJoin} conferenceUri={this.state.videoCallUri} audio={this.videoCallAudio} userInfo={this.state.data.user_info} />
-            </View>
-        );
-    }
+function UnaApp(o) {
+        const styles = useDynamicStyleSheet(dynamicStyles);
 
 
-    renderToolbar () {
-        return (        
-            <Header>
-                <Left>
-                    {this.state.data.loggedin ? (
-                        <Button style={Platform.OS === 'android' ? styles.buttonLeftTopAndroid : styles.buttonLeftTopIos} transparent onPress={this.onBackAndMainMenu.bind(this)} disabled={this.state.backButtonEnabled ? false : true}>
-                            <Icon name="ios-arrow-back" />
-                        </Button>
-                    ) : (
-                        <Button style={Platform.OS === 'android' ? styles.buttonLeftTopAndroid : styles.buttonLeftTopIos} transparent onPress={this.onMainMenu.bind(this)}>
-                            <Icon name='menu' />
-                        </Button>
-                    )}
-                </Left>
-                <Body>            
-                    <Title onPress={this.onHomeMenu.bind(this)}>{TITLE}</Title>
-                </Body>
-                <Right>
-                    {this.state.data.loggedin && (
-                        <Button transparent>
-                            <Icon name='search' onPress={this.onSearchMenu.bind(this)} />
-                        </Button>
-                    )}
-                </Right>
-            </Header>
-        );
-    }
-    
-    renderToolbarSearch () {
-        return (
-            <Header searchBar rounded>
-              <Item>
-                <Icon name="search" />
-                <Input ref="inputSearch" placeholder="Search" onEndEditing={this.onSearchCancelMenu.bind(this)} onSubmitEditing={this.onSearch.bind(this)} />
-              </Item>
-              <Button transparent onPress={this.onSearchCancelMenu.bind(this)}>
-                <Text>Cancel</Text>
-              </Button>
-            </Header>
-        );
-    }
+        const isDarkMode = useDarkMode();
+        var sBarStyle = 'dark-content';
+        if (Platform.OS === 'android' || isDarkMode)
+            sBarStyle = 'light-content';
+        StatusBar.setBarStyle(sBarStyle, false); 
 
 
-    renderLoadingView () {
-        return (
-            <View style={styles.viewLoading}>
-                <Image source={require('./img/logo-loading.png')} />
-                <Text>Loading...</Text>
-            </View>
-        );
-    }
+        return (<Container>
 
 
-    renderDrawer () {
-        return (
-            <Container>
-                <Content>
-                    <View style={styles.drawerImageContainer}>
-                        <Image style={styles.drawerImage} source={require('./img/logo-loading.png')} />
+                {o.state.searchbar ? (
+                    <UnaToolbarSearch onSearch={o.onSearch} onSearchCancel={o.onSearchCancelMenu} />
+                ) : (
+                    <UnaToolbar loggedin={o.state.data.loggedin} backButtonEnabled={o.state.backButtonEnabled} onMainMenu={o.onMainMenu} onHomeMenu={o.onHomeMenu} onSearchMenu={o.onSearchMenu} />
+                ) }
+
+                {o.state.videoCall && o.state.videoCallUri ? (
+                    <View style={styles.containerVideoCall}><VideoCall onConferenceTerminated={o.onConferenceTerminated} onConferenceJoined={o.onConferenceJoined} onConferenceWillJoin={o.onConferenceWillJoin} conferenceUri={o.state.videoCallUri} audio={o.videoCallAudio} userInfo={o.state.data.user_info} /></View>
+                ) : (
+                    <View />
+                )}
+
+                {o.webview}
+
+                {o.state.data.loggedin && (
+                    <UnaFooter bubblesNum={o.state.data.bubbles_num} bubbles={o.state.data.bubbles} onMainMenu={o.onMainMenu} onNotificationsMenu={o.onNotificationsMenu} onVideoCallToggle={o.onVideoCallToggle} onAddMenu={o.onAddMenu} onMessengerMenu={o.onMessengerMenu} onProfileMenu={o.onProfileMenu} />
+                )}
+
+                {o.state.loading && (
+                    <View style={styles.viewLoading2}>
+                        <ActivityIndicator size="large" color="#fff" />
                     </View>
                     </View>
-                    <Button style={styles.drawerButton} iconLeft transparent onPress={this.onDrawerLoginMenu.bind(this)}>
-                        <Icon style={styles.drawerButtonIcon} name='key' type="FontAwesome5" solid />
-                        <Text>Login</Text>
+                )}
+
+                </Container>
+        );
+}
+
+function UnaFooter(o) {
+    const styles = useDynamicStyleSheet(dynamicStyles)
+    return (
+        <Footer style={styles.footer}>
+            <FooterTab>
+                <Button vertical onPress={o.onMainMenu}>
+                    <Icon name="bars" type="FontAwesome5" />
+                </Button>
+            </FooterTab>
+            <FooterTab>
+                <Button vertical onPress={o.onNotificationsMenu} badge={o.bubbles['notifications-notifications'] > 0 ? true : false}>
+                    {o.bubbles['notifications-notifications'] > 0 && 
+                        (<Badge><Text>{o.bubbles['notifications-notifications']}</Text></Badge>)
+                    }
+                    <Icon name="bell" type="FontAwesome5" solid />
+                </Button>
+            </FooterTab>
+{/*
+            <FooterTab>
+                <Button vertical onPress={o.onVideoCallToggle}>
+                    <Icon name="video" type="FontAwesome5" solid />
+                </Button>
+            </FooterTab>
+*/}
+            <FooterTab>
+                <Button vertical onPress={o.onAddMenu}>
+                    <Icon name="plus-circle" type="FontAwesome5" solid />
+                </Button>
+            </FooterTab>
+            <FooterTab>
+                <Button vertical onPress={o.onMessengerMenu} badge={o.bubbles['notifications-messenger'] > 0 ? true : false}>
+                    {o.bubbles['notifications-messenger'] > 0 && 
+                        (<Badge><Text>{o.bubbles['notifications-messenger']}</Text></Badge>)
+                    }
+                    <Icon name="comments" type="FontAwesome5" solid />
+                </Button>
+            </FooterTab>                    
+            <FooterTab>
+                <Button vertical onPress={o.onProfileMenu} badge={o.bubblesNum > 0 ? true : false}>
+                    {o.bubblesNum > 0 && 
+                        (<Badge><Text>{o.bubblesNum}</Text></Badge>)
+                    }
+                    <Icon name="user" type="FontAwesome5" solid />
+                </Button>
+            </FooterTab>
+        </Footer>
+    );
+}
+
+function UnaToolbar(o) {
+    const styles = useDynamicStyleSheet(dynamicStyles)
+    return (
+        <Header style={styles.header}>
+            <Left>
+                {o.loggedin ? (
+                    <Button style={Platform.OS === 'android' ? styles.buttonLeftTopAndroid : styles.buttonLeftTopIos} transparent onPress={o.onBackAndMainMenu} disabled={!o.backButtonEnabled}>
+                        <Icon name="ios-arrow-back" />
                     </Button>
                     </Button>
-                    <Button style={styles.drawerButton} iconLeft transparent onPress={this.onDrawerJoinMenu.bind(this)}>
-                        <Icon style={styles.drawerButtonIcon} name='plus-circle' type="FontAwesome5" solid />
-                        <Text>Join</Text>
+                ) : (
+                    <Button style={Platform.OS === 'android' ? styles.buttonLeftTopAndroid : styles.buttonLeftTopIos} transparent onPress={o.onMainMenu}>
+                        <Icon name='menu' />
                     </Button>
                     </Button>
-                    <Button style={styles.drawerButton} iconLeft transparent onPress={this.onDrawerForgotMenu.bind(this)}>
-                        <Icon style={styles.drawerButtonIcon} name='lock' type="FontAwesome5" solid />
-                        <Text>Forgot Password</Text>
+                )}
+            </Left>
+            <Body>            
+                <Title style={styles.headerTitle} onPress={o.onHomeMenu}>{TITLE}</Title>
+            </Body>
+            <Right>
+                {o.loggedin && (
+                    <Button transparent>
+                        <Icon name='search' onPress={o.onSearchMenu} />
                     </Button>
                     </Button>
-                </Content>
-            </Container>
-        );
-    }
+                )}
+            </Right>
+        </Header>
+    );
 }
 }
 
 
-const styles = StyleSheet.create({
+function UnaToolbarSearch(o) {
+    const styles = useDynamicStyleSheet(dynamicStyles)
+    return (
+        <Header style={styles.header} searchBar rounded>
+          <Item>
+            <Icon name="search" />
+            <Input placeholder="Search" onEndEditing={o.onSearchCancel} onSubmitEditing={o.onSeach} />
+          </Item>
+          <Button transparent onPress={o.onSearchCancel}>
+            <Text>Cancel</Text>
+          </Button>
+        </Header>
+    );
+}
+
+function UnaDrawer(o) {
+    const styles = useDynamicStyleSheet(dynamicStyles)
+    return (
+        <Container>
+            <Content>
+                <View style={styles.drawerImageContainer}>
+                    <Image style={styles.drawerImage} source={require('./img/logo-loading.png')} />
+                </View>
+                <Button style={styles.drawerButton} iconLeft transparent onPress={o.onLogin}>
+                    <Icon style={styles.drawerButtonIcon} name='key' type="FontAwesome5" solid />
+                    <Text>Login</Text>
+                </Button>
+                <Button style={styles.drawerButton} iconLeft transparent onPress={o.onJoin}>
+                    <Icon style={styles.drawerButtonIcon} name='plus-circle' type="FontAwesome5" solid />
+                    <Text>Join</Text>
+                </Button>
+                <Button style={styles.drawerButton} iconLeft transparent onPress={o.onForotPassword}>
+                    <Icon style={styles.drawerButtonIcon} name='lock' type="FontAwesome5" solid />
+                    <Text>Forgot Password</Text>
+                </Button>
+            </Content>
+        </Container>
+  );
+}
+
+const dynamicStyles = new DynamicStyleSheet({
+    header: {
+        backgroundColor: new DynamicValue('#eee', '#333'),
+    },
+    headerTitle: {
+        color: new DynamicValue('#333', '#eee'),
+    },
+    footer: {
+        backgroundColor: new DynamicValue('#eee', '#333'),
+    },
+
     containerVideoCall: {
     containerVideoCall: {
         backgroundColor: '#000',
         backgroundColor: '#000',
         flex: 999999999999,
         flex: 999999999999,
     },
     },
-    containerWebView: {
-        flex: 1,
-    },
-    viewLoading: {
-        position: 'absolute', 
-        top: 0, 
-        left: 0, 
-        right: 0, 
-        bottom: 0, 
-        justifyContent: 'center', 
-        alignItems: 'center', 
-        backgroundColor: '#FFF',
-    },
     viewLoading2: {
     viewLoading2: {
         position: 'absolute',
         position: 'absolute',
         width: Dimensions.get('window').width,
         width: Dimensions.get('window').width,

+ 6 - 0
ios/Podfile.lock

@@ -304,6 +304,8 @@ PODS:
     - React-cxxreact (= 0.62.1)
     - React-cxxreact (= 0.62.1)
     - React-jsi (= 0.62.1)
     - React-jsi (= 0.62.1)
     - ReactCommon/callinvoker (= 0.62.1)
     - ReactCommon/callinvoker (= 0.62.1)
+  - ReactNativeDarkMode (0.2.2):
+    - React
   - Yoga (1.14.0)
   - Yoga (1.14.0)
   - YogaKit (1.18.1):
   - YogaKit (1.18.1):
     - Yoga (~> 1.14)
     - Yoga (~> 1.14)
@@ -345,6 +347,7 @@ DEPENDENCIES:
   - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
   - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
   - ReactCommon/callinvoker (from `../node_modules/react-native/ReactCommon`)
   - ReactCommon/callinvoker (from `../node_modules/react-native/ReactCommon`)
   - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
   - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
+  - ReactNativeDarkMode (from `../node_modules/react-native-dark-mode`)
   - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
   - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
 
 
 SPEC REPOS:
 SPEC REPOS:
@@ -421,6 +424,8 @@ EXTERNAL SOURCES:
     :path: "../node_modules/react-native/Libraries/Vibration"
     :path: "../node_modules/react-native/Libraries/Vibration"
   ReactCommon:
   ReactCommon:
     :path: "../node_modules/react-native/ReactCommon"
     :path: "../node_modules/react-native/ReactCommon"
+  ReactNativeDarkMode:
+    :path: "../node_modules/react-native-dark-mode"
   Yoga:
   Yoga:
     :path: "../node_modules/react-native/ReactCommon/yoga"
     :path: "../node_modules/react-native/ReactCommon/yoga"
 
 
@@ -466,6 +471,7 @@ SPEC CHECKSUMS:
   React-RCTText: 239e040f401505001327a109f9188a4e6dad1bd2
   React-RCTText: 239e040f401505001327a109f9188a4e6dad1bd2
   React-RCTVibration: 072c3b427dd29e730c2ee5bfc509cf5054741a50
   React-RCTVibration: 072c3b427dd29e730c2ee5bfc509cf5054741a50
   ReactCommon: 3585806280c51d5c2c0d3aa5a99014c3badb629d
   ReactCommon: 3585806280c51d5c2c0d3aa5a99014c3badb629d
+  ReactNativeDarkMode: 0178ffca3b10f6a7c9f49d6f9810232b328fa949
   Yoga: 50fb6eb13d2152e7363293ff603385db380815b1
   Yoga: 50fb6eb13d2152e7363293ff603385db380815b1
   YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
   YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
 
 

+ 3 - 0
ios/una/Info.plist

@@ -81,11 +81,14 @@
 	<array>
 	<array>
 		<string>armv7</string>
 		<string>armv7</string>
 	</array>
 	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
 	<key>UISupportedInterfaceOrientations</key>
 	<key>UISupportedInterfaceOrientations</key>
 	<array>
 	<array>
 		<string>UIInterfaceOrientationPortrait</string>
 		<string>UIInterfaceOrientationPortrait</string>
 		<string>UIInterfaceOrientationLandscapeLeft</string>
 		<string>UIInterfaceOrientationLandscapeLeft</string>
 		<string>UIInterfaceOrientationLandscapeRight</string>
 		<string>UIInterfaceOrientationLandscapeRight</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 	</array>
 	</array>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<false/>
 	<false/>

+ 55 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "UNA",
   "name": "UNA",
-  "version": "1.3.3",
+  "version": "1.4.0",
   "lockfileVersion": 1,
   "lockfileVersion": 1,
   "requires": true,
   "requires": true,
   "dependencies": {
   "dependencies": {
@@ -1259,6 +1259,11 @@
       "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
       "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
       "dev": true
       "dev": true
     },
     },
+    "@types/events": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
+      "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
+    },
     "@types/istanbul-lib-coverage": {
     "@types/istanbul-lib-coverage": {
       "version": "2.0.1",
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
@@ -1287,6 +1292,28 @@
       "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
       "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
       "dev": true
       "dev": true
     },
     },
+    "@types/prop-types": {
+      "version": "15.7.3",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
+      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
+    },
+    "@types/react": {
+      "version": "16.9.34",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.34.tgz",
+      "integrity": "sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow==",
+      "requires": {
+        "@types/prop-types": "*",
+        "csstype": "^2.2.0"
+      }
+    },
+    "@types/react-native": {
+      "version": "0.62.4",
+      "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.4.tgz",
+      "integrity": "sha512-AKImyybUzqqPItKNuURkMe7y1X5cxuSJh5td8qbFSEXO58S5qjw01eZweWkKyTVCvrWGXkfm43u1zoYcZSGL6w==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/stack-utils": {
     "@types/stack-utils": {
       "version": "1.0.1",
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
@@ -2470,6 +2497,11 @@
         "cssom": "0.3.x"
         "cssom": "0.3.x"
       }
       }
     },
     },
+    "csstype": {
+      "version": "2.6.10",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz",
+      "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w=="
+    },
     "dashdash": {
     "dashdash": {
       "version": "1.14.1",
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -3099,6 +3131,11 @@
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
       "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
       "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
     },
     },
+    "events": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
+      "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg=="
+    },
     "exec-sh": {
     "exec-sh": {
       "version": "0.3.4",
       "version": "0.3.4",
       "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
       "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
@@ -7578,6 +7615,18 @@
         }
         }
       }
       }
     },
     },
+    "react-native-dark-mode": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/react-native-dark-mode/-/react-native-dark-mode-0.2.2.tgz",
+      "integrity": "sha512-2vhWOOimU7DRKYjCU/pdv0+JpnGKURq5+c7bre093Jtzk57HtlJfd+ViibbC9Y8zh0viIOyKtfL5mYhVhZ6Crw==",
+      "requires": {
+        "@types/events": "*",
+        "@types/react": "*",
+        "@types/react-native": "*",
+        "events": "^3.0.0",
+        "toolkit.ts": "^0.0.2"
+      }
+    },
     "react-native-drawer": {
     "react-native-drawer": {
       "version": "2.5.1",
       "version": "2.5.1",
       "resolved": "https://registry.npmjs.org/react-native-drawer/-/react-native-drawer-2.5.1.tgz",
       "resolved": "https://registry.npmjs.org/react-native-drawer/-/react-native-drawer-2.5.1.tgz",
@@ -8853,6 +8902,11 @@
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
     },
     },
+    "toolkit.ts": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/toolkit.ts/-/toolkit.ts-0.0.2.tgz",
+      "integrity": "sha512-yJJTVbCwiD6AfFgReewJCGJuODmyZUeL1sDjnxp33t0UBxnezgQrLbz/F9++RC28CTlk5u5pVji4TbeondYEkw=="
+    },
     "tough-cookie": {
     "tough-cookie": {
       "version": "2.5.0",
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "native-base": "^2.13.12",
     "native-base": "^2.13.12",
     "react": "16.11.0",
     "react": "16.11.0",
     "react-native": "0.62.1",
     "react-native": "0.62.1",
+    "react-native-dark-mode": "^0.2.2",
     "react-native-jitsi-meet": "^2.1.1",
     "react-native-jitsi-meet": "^2.1.1",
     "react-native-onesignal": "^3.7.1",
     "react-native-onesignal": "^3.7.1",
     "react-native-splash-screen": "^3.2.0",
     "react-native-splash-screen": "^3.2.0",