Skip to content

Commit

Permalink
Merge pull request #25 from kanzitelli/services-improvements
Browse files Browse the repository at this point in the history
Services improvements
  • Loading branch information
kanzitelli committed Dec 20, 2020
2 parents 5c33b01 + b607fc2 commit fca6d1f
Show file tree
Hide file tree
Showing 25 changed files with 364 additions and 317 deletions.
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [🧙‍♂️ Enhancements](#enhancements)
- [⚠️ Known issues (warnings)](#known-issues-warnings)
- [⭕️ Limitations](#limitations)
- [🤓 Worth checking](#worth-checking)

## Motivation
1. I love [React Native](https://reactnative.dev/) 💚
Expand Down Expand Up @@ -62,9 +63,11 @@ yarn android
- [Typescript](https://www.typescriptlang.org/) - strict syntactical superset of JavaScript
### Small useful services/hooks from me
- `useStyles()` - a hook that takes care of dark mode in your app. Supports toggling modes while you are in app. No dependencies (needs only `react-native`, so could be reusable).
- `appUpdates` - a service that shows and simplifies integration with `expo-updates`. In order to use it, you will need to change `Expo.plist` and `AndroidManifest.xml` with your actual information. More information about [expo-updates](https://docs.expo.io/versions/latest/sdk/updates/).
- `useConstants()` - a simple hook that gives access to constants.
- `navigation` - a service where all navigation configuration takes place. It might be a bit confusing but it should simplify and abstract the process of registering screens, etc.
- `translate` - a service that shows and simplifies integration with `expo-localization` and `i18n-js`. You can see an example of `en`, `ru` and `de` localizations in `ExpoScreen`.
- `notifications` - a service that takes care of setting up notifications which utilizes [React Native Notifications](https://github.com/wix/react-native-notifications). For more information, please, take a look at this [guide](/NOTIFICATIONS.md).
- `appUpdates` - a service that shows and simplifies integration with `expo-updates`. In order to use it, you will need to change `Expo.plist` and `AndroidManifest.xml` with your actual information. More information about [expo-updates](https://docs.expo.io/versions/latest/sdk/updates/).

## Enhancements
There are still some things I would like to add to the starter:
Expand All @@ -85,6 +88,16 @@ Feel free to open an issue for any other warning or problems.
- Apps bootstrapped from this starter won't be able to be run on web as Expo apps do. Theoretically, it is possible to create some sort of an adapter between `react-navigation` and `react-native-navigation`. Maybe there will be other issues, but would be cool to have this feature.
- Apps bootstrapped from this starter won't be available through Expo app for iOS and Android as of differences in navigation approach. Theoretically, it is possible to create an app like Expo that will include `react-native-navigation` and somehow download needed bundles. Needs more research.

## License
## Worth checking
### Articles
- Expo + React Native Navigation? Yes! - [Medium](https://kanzitelli.medium.com/expo-react-native-navigation-yes-ebda0cbfa4b1), [Dev.to](https://dev.to/kanzitelli/expo-react-native-navigation-1pll)

### Apps in production
- Rabbit App. Lite Reddit client - [Github](https://github.com/kanzitelli/rabbit-app), [App Store](https://apps.apple.com/ru/app/rabbit-app-lite-reddit-client/id1535084154), [Google Play](https://play.google.com/store/apps/details?id=io.batyr.rabbitapp)
- Christmas Market - [App Store](https://apps.apple.com/ru/app/id1446775875)
- Trip Music Radio - [App Store](https://apps.apple.com/ru/app/id1525645826), [Google Play](https://play.google.com/store/apps/details?id=team.ggc.tripmusic)
- Messenger for VK - [App Store](https://apps.apple.com/ru/app/id891605076)
- App for VK - [App Store](https://apps.apple.com/ru/app/id819406913)

## License
This project is [MIT licensed](/LICENSE.md)
91 changes: 8 additions & 83 deletions src/App.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,6 @@
import { Navigation } from 'react-native-navigation';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
import Ionicons from 'react-native-vector-icons/Ionicons';

import Constants from './utils/constants';

import CounterScreen from './screens/CounterScreen';
import ExpoScreen from './screens/ExpoScreen';

import { withStoresProvider, hydrateStores } from './stores';
import { withServicesProvider, initServices } from './services';
import { setOptionsForUseStyles } from './utils/useStyles';

const Screens = new Map<string, React.FC<any>>();

Screens.set(Constants.ScreenNames.CounterScreen, CounterScreen);
Screens.set(Constants.ScreenNames.ExpoScreen, ExpoScreen);

// Register screens
Screens.forEach((C, key) => {
Navigation.registerComponent(
key,
() =>
gestureHandlerRootHOC(
withStoresProvider(
withServicesProvider(C))),
() => C,
);
});

// Here some global listeners could be placed
// ...
import { hydrateStores } from './stores';
import { initServices, services } from './services';
import { setOptionsForUseStyles } from './hooks/useStyles';

export const startApp = async () => {
// rehydrate stores
Expand All @@ -38,57 +9,11 @@ export const startApp = async () => {
// init services
await initServices();

// getting icons for tabs as they have to be as image sources
const [tab1, tab2] = await Promise.all([
Ionicons.getImageSource('ios-duplicate-outline', 25),
Ionicons.getImageSource('ios-rocket-outline', 25),
]);
const [tab1Selected, tab2Selected] = await Promise.all([
Ionicons.getImageSource('ios-duplicate', 25),
Ionicons.getImageSource('ios-rocket', 25),
]);

// (optional) set options for useStyles
// setOptionsForUseStyles({
// normalize: false,
// darkmode: false,
// });

Navigation.setRoot({
root: {
bottomTabs: {
children: [{
stack: {
children: [{
component: {
name: Constants.ScreenNames.CounterScreen,
},
}],
options: {
bottomTab: {
text: Constants.BottomTabsTitles.tab1,
icon: tab1,
selectedIcon: tab1Selected,
},
},
},
}, {
stack: {
children: [{
component: {
name: Constants.ScreenNames.ExpoScreen,
},
}],
options: {
bottomTab: {
text: Constants.BottomTabsTitles.tab2,
icon: tab2,
selectedIcon: tab2Selected,
},
},
},
}],
},
},
setOptionsForUseStyles({
normalize: true,
darkmode: true,
});

services.nav.startApp();
};
2 changes: 1 addition & 1 deletion src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import AntIcon from 'react-native-vector-icons/AntDesign';
import { TouchableOpacity } from 'react-native-gesture-handler';

import useStyles from '../utils/useStyles';
import useStyles from '../hooks/useStyles';

type ButtonTitleProps = {
title: string;
Expand Down
40 changes: 0 additions & 40 deletions src/components/NView.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/example-component.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';

import useStyles from '../utils/useStyles';
import useStyles from '../hooks/useStyles';

type ExampleComponentProps = {
}
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/useConstants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const useContants = () => {
return {
colors: {
main: '#4d7198',
black: '#000',
white: '#fff',
lightGrey: '#dcdde1',
blue: '#4d7198',
yellow: '#fbc531',
},
sizes: {
xs: 4,
s: 8,
m: 16,
l: 24,
xl: 32,
xxl: 40,
}
}
}

export default useContants;
4 changes: 2 additions & 2 deletions src/utils/useStyles.ts → src/hooks/useStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useEffect, useState } from 'react';
import { Appearance, Dimensions, Platform, PixelRatio } from 'react-native';
import { isTablet } from 'react-native-device-info';

import Constants from './constants';
import useConstants from './useConstants';

const { colors, sizes } = Constants;
const { colors, sizes } = useConstants();
let options: UseStylesOptionsType = {
normalize: true,
darkmode: true,
Expand Down
38 changes: 6 additions & 32 deletions src/screens/CounterScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@ import {
Text,
View,
StyleSheet,
Platform,
ActivityIndicator,
Pressable,
} from 'react-native';
import { observer } from 'mobx-react';
import { NavigationFunctionComponent } from 'react-native-navigation';
import { useNavigationButtonPress } from 'react-native-navigation-hooks/dist/hooks';

import { useStores } from '../stores';
import { useServices } from '../services';
import Constants from '../utils/constants';
import { ButtonIcon } from '../components/Button';
import useStyles from '../utils/useStyles';
import { TouchableOpacity } from 'react-native-gesture-handler';
import useStyles from '../hooks/useStyles';
import { ScreenOptions } from '../services/navigation/screens';
import { Buttons } from '../services/navigation/buttons';

const CounterScreen: NavigationFunctionComponent = observer(({
componentId,
Expand All @@ -26,8 +23,8 @@ const CounterScreen: NavigationFunctionComponent = observer(({
const { } = useServices();
const { styles } = useStyles(_styles);

useNavigationButtonPress(counter.decrement, componentId, Constants.CounterScreen.decButtonId);
useNavigationButtonPress(counter.increment, componentId, Constants.CounterScreen.incButtonId);
useNavigationButtonPress(counter.decrement, componentId, Buttons.Dec.id);
useNavigationButtonPress(counter.increment, componentId, Buttons.Inc.id);

return (
<SafeAreaView style={styles.container}>
Expand Down Expand Up @@ -75,29 +72,6 @@ const _styles = (theme: ThemeType) => StyleSheet.create({
},
});

CounterScreen.options = props => ({
topBar: {
leftButtons: Platform.OS === 'ios' ? [{
id: Constants.CounterScreen.decButtonId,
text: Constants.CounterScreen.decButtonTitle,
}] : [],
rightButtons: Platform.OS === 'ios' ? [{
id: Constants.CounterScreen.incButtonId,
text: Constants.CounterScreen.incButtonTitle,
}] : [{
id: Constants.CounterScreen.incButtonId,
text: Constants.CounterScreen.incButtonTitle,
}, {
id: Constants.CounterScreen.decButtonId,
text: Constants.CounterScreen.decButtonTitle,
}],
title: {
text: Constants.ScreenTitles.CounterScreen,
},
largeTitle: {
visible: true,
},
},
});
CounterScreen.options = props => ScreenOptions.CounterScreen;

export default CounterScreen;
2 changes: 1 addition & 1 deletion src/screens/ExpoApp.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';

import useStyles from '../utils/useStyles';
import useStyles from '../hooks/useStyles';

// This component is used to pass it to registerRootComponent(...) for Expo SDK
// Otherwise, it was causing a crash on iOS (14?) in release build
Expand Down
27 changes: 8 additions & 19 deletions src/screens/ExpoScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import {
SafeAreaView,
Text,
View,
StyleSheet,
Expand All @@ -14,21 +13,20 @@ import { ScrollView } from 'react-native-gesture-handler';
import { Constants as ExpoConstants } from 'react-native-unimodules';
import * as Network from 'expo-network';

import Constants from '../utils/constants';
import { useStores } from '../stores';
import { useServices } from '../services';
import Reanimated2 from '../components/Reanimated2';
import { ButtonTitle } from '../components/Button';
import useStyles from '../utils/useStyles';
import NView from '../components/NView';
import useStyles from '../hooks/useStyles';
import { ScreenOptions } from '../services/navigation/screens';

type ExpoScreenProps = { }

const ExpoScreen: NavigationFunctionComponent<ExpoScreenProps> = observer(({
componentId,
}) => {
const { ui } = useStores();
const { navigation, t } = useServices();
const { nav, t } = useServices();
const { styles } = useStyles(_styles);

useNavigationComponentDidAppear(() => {
Expand Down Expand Up @@ -70,15 +68,15 @@ const ExpoScreen: NavigationFunctionComponent<ExpoScreenProps> = observer(({

<ButtonTitle
title={t.do('push_screen')}
onPress={() => navigation.pushExpo(componentId)}
onPress={() => nav.pushExpo(componentId)}
/>
<ButtonTitle
title={t.do('show_modal')}
onPress={() => navigation.showExpo()}
onPress={() => nav.showExpo()}
/>
<ButtonTitle
title={t.do('close_modal')}
onPress={() => navigation.dismissModal(componentId)}
onPress={() => nav.dismissModal(componentId)}
/>
</View>
</ScrollView>
Expand Down Expand Up @@ -106,15 +104,6 @@ const _styles = (theme: ThemeType) => StyleSheet.create({
}
});

ExpoScreen.options = props => ({
topBar: {
title: {
text: Constants.ScreenTitles.ExpoScreen,
},
largeTitle: {
visible: true,
}
},
});
ExpoScreen.options = props => ScreenOptions.ExpoScreen;

export default ExpoScreen;
Loading

0 comments on commit fca6d1f

Please sign in to comment.