verdnatura-chat/app/share.tsx

226 lines
6.0 KiB
TypeScript

import React, { useContext } from 'react';
import { Dimensions } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { AppearanceProvider } from 'react-native-appearance';
import { createStackNavigator } from '@react-navigation/stack';
import { Provider } from 'react-redux';
import { defaultTheme, newThemeState, subscribeTheme, unsubscribeTheme } from './utils/theme';
import UserPreferences from './lib/userPreferences';
import Navigation from './lib/ShareNavigation';
import store from './lib/createStore';
import { supportSystemTheme } from './utils/deviceInfo';
import { defaultHeader, themedHeader, getActiveRouteName, navigationTheme } from './utils/navigation';
import RocketChat, { THEME_PREFERENCES_KEY } from './lib/rocketchat';
import { ThemeContext } from './theme';
import { localAuthenticate } from './utils/localAuthentication';
import ScreenLockedView from './views/ScreenLockedView';
// Outside Stack
import WithoutServersView from './views/WithoutServersView';
// Inside Stack
import ShareListView from './views/ShareListView';
import ShareView from './views/ShareView';
import SelectServerView from './views/SelectServerView';
import { setCurrentScreen } from './utils/log';
import AuthLoadingView from './views/AuthLoadingView';
import { DimensionsContext } from './dimensions';
import debounce from './utils/debounce';
type TDimensions = {
width: number,
height: number,
scale: number,
fontScale: number
}
interface IProps {}
interface IState {
theme: string,
themePreferences: {
currentTheme: 'automatic' | 'light',
darkLevel: string
},
root: any;
width: number;
height: number;
scale: number;
fontScale: number;
}
const Inside = createStackNavigator();
const InsideStack = () => {
const { theme } = useContext(ThemeContext);
const screenOptions = {
...defaultHeader,
...themedHeader(theme)
};
screenOptions.headerStyle = {...screenOptions.headerStyle, height: 57};
return (
<Inside.Navigator screenOptions={screenOptions}>
<Inside.Screen
name='ShareListView'
component={ShareListView}
/>
<Inside.Screen
name='ShareView'
component={ShareView}
/>
<Inside.Screen
name='SelectServerView'
component={SelectServerView}
options={SelectServerView.navigationOptions}
/>
</Inside.Navigator>
);
};
const Outside = createStackNavigator();
const OutsideStack = () => {
const { theme } = useContext(ThemeContext);
return (
<Outside.Navigator screenOptions={{ ...defaultHeader, ...themedHeader(theme) }}>
<Outside.Screen
name='WithoutServersView'
component={WithoutServersView}
/*@ts-ignore*/
options={WithoutServersView.navigationOptions}
/>
</Outside.Navigator>
);
};
// App
const Stack = createStackNavigator();
export const App = ({ root }: any) => (
<Stack.Navigator screenOptions={{ headerShown: false, animationEnabled: false }}>
<>
{!root ? (
<Stack.Screen
name='AuthLoading'
component={AuthLoadingView}
/>
) : null}
{root === 'outside' ? (
<Stack.Screen
name='OutsideStack'
component={OutsideStack}
/>
) : null}
{root === 'inside' ? (
<Stack.Screen
name='InsideStack'
component={InsideStack}
/>
) : null}
</>
</Stack.Navigator>
);
class Root extends React.Component<IProps, IState> {
constructor(props: any) {
super(props);
const { width, height, scale, fontScale } = Dimensions.get('screen');
this.state = {
theme: defaultTheme(),
themePreferences: {
currentTheme: supportSystemTheme() ? 'automatic' : 'light',
darkLevel: 'black'
},
root: '',
width,
height,
scale,
fontScale
};
this.init();
}
componentWillUnmount() {
RocketChat.closeShareExtension();
unsubscribeTheme();
}
init = async() => {
UserPreferences.getMapAsync(THEME_PREFERENCES_KEY).then(() => this.setTheme());
const currentServer = await UserPreferences.getStringAsync(RocketChat.CURRENT_SERVER);
if (currentServer) {
await localAuthenticate(currentServer);
this.setState({ root: 'inside' });
await RocketChat.shareExtensionInit(currentServer);
} else {
this.setState({ root: 'outside' });
}
const state = Navigation.navigationRef.current?.getRootState();
const currentRouteName = getActiveRouteName(state);
Navigation.routeNameRef.current = currentRouteName;
setCurrentScreen(currentRouteName);
}
setTheme = (newTheme = {}) => {
// change theme state
this.setState(prevState => newThemeState(prevState, newTheme), () => {
const { themePreferences } = this.state;
// subscribe to Appearance changes
subscribeTheme(themePreferences, this.setTheme);
});
}
// Dimensions update fires twice
onDimensionsChange = debounce(({window: { width, height, scale, fontScale}}: {window: TDimensions}) => {
this.setDimensions({ width, height, scale, fontScale });
})
setDimensions = ({ width, height, scale, fontScale }: TDimensions) => {
this.setState({
width, height, scale, fontScale
});
}
render() {
const { theme, root, width, height, scale, fontScale } = this.state;
const navTheme = navigationTheme(theme);
return (
<AppearanceProvider>
<Provider store={store}>
<ThemeContext.Provider value={{ theme }}>
<DimensionsContext.Provider
value={{
width,
height,
scale,
fontScale,
setDimensions: this.setDimensions
}}
>
<NavigationContainer
theme={navTheme}
ref={Navigation.navigationRef}
onStateChange={(state) => {
const previousRouteName = Navigation.routeNameRef.current;
const currentRouteName = getActiveRouteName(state);
if (previousRouteName !== currentRouteName) {
setCurrentScreen(currentRouteName);
}
Navigation.routeNameRef.current = currentRouteName;
}}
>
<App root={root} />
</NavigationContainer>
<ScreenLockedView />
</DimensionsContext.Provider>
</ThemeContext.Provider>
</Provider>
</AppearanceProvider>
);
}
}
export default Root;