Compare commits

..

8 commits

25 changed files with 202 additions and 335 deletions

View file

@ -80,8 +80,8 @@ project.ext.react = [
enableHermes: true,
]
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
/**
* Set this to true to create two separate APKs instead of one:
@ -134,6 +134,7 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 16
versionName "2.0.0"
missingDimensionStrategy 'react-native-camera', 'general'
}
splits {
abi {
@ -190,7 +191,6 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules
addUnimodulesDependencies()
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";

View file

@ -9,16 +9,6 @@ import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import fr.amicaleinsat.application.generated.BasePackageList;
import org.unimodules.adapters.react.ReactAdapterPackage;
import org.unimodules.adapters.react.ModuleRegistryAdapter;
import org.unimodules.adapters.react.ReactModuleRegistryProvider;
import org.unimodules.core.interfaces.Package;
import org.unimodules.core.interfaces.SingletonModule;
import expo.modules.constants.ConstantsPackage;
import expo.modules.permissions.PermissionsPackage;
import expo.modules.filesystem.FileSystemPackage;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
@ -26,10 +16,6 @@ import java.util.List;
import javax.annotation.Nullable;
public class MainApplication extends Application implements ReactApplication {
private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(
new BasePackageList().getPackageList(),
null
);
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
@ -40,7 +26,6 @@ public class MainApplication extends Application implements ReactApplication {
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));
return packages;
}

View file

@ -1,25 +0,0 @@
package fr.amicaleinsat.application.generated;
import java.util.Arrays;
import java.util.List;
import org.unimodules.core.interfaces.Package;
public class BasePackageList {
public List<Package> getPackageList() {
return Arrays.<Package>asList(
new expo.modules.barcodescanner.BarCodeScannerPackage(),
new expo.modules.camera.CameraPackage(),
new expo.modules.constants.ConstantsPackage(),
new expo.modules.errorrecovery.ErrorRecoveryPackage(),
new expo.modules.filesystem.FileSystemPackage(),
new expo.modules.font.FontLoaderPackage(),
new expo.modules.imageloader.ImageLoaderPackage(),
new expo.modules.keepawake.KeepAwakePackage(),
new expo.modules.lineargradient.LinearGradientPackage(),
new expo.modules.location.LocationPackage(),
new expo.modules.permissions.PermissionsPackage(),
new expo.modules.sqlite.SQLitePackage(),
new expo.modules.webbrowser.WebBrowserPackage()
);
}
}

View file

@ -1,8 +1,5 @@
rootProject.name = 'Campus'
apply from: '../node_modules/react-native-unimodules/gradle.groovy'
includeUnimodulesProjects()
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle");
applyNativeModulesSettingsGradle(settings)

View file

@ -1,11 +1,3 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo', '@babel/preset-flow'],
env: {
production: {
plugins: ['react-native-paper/babel'],
},
},
};
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};

View file

@ -1,8 +1,4 @@
import {registerRootComponent} from 'expo';
import {AppRegistry} from 'react-native';
import App from './App';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in the Expo client or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
AppRegistry.registerComponent('main', () => App);

View file

@ -71,5 +71,9 @@
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIAppFonts</key>
<array>
<string>MaterialCommunityIcons.ttf</string>
</array>
</dict>
</plist>

View file

@ -50,4 +50,7 @@ target 'Campus' do
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec"
pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
# Vector Icons
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
end

17
metro.config.js Normal file
View file

@ -0,0 +1,17 @@
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
*
* @format
*/
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};

View file

@ -1,12 +1,13 @@
{
"name": "campus",
"version": "2.0.0",
"private": true,
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"web": "expo start --web",
"test": "jest",
"testw": "jest --watch",
"testc": "jest --coverage"
"lint": "eslint ."
},
"jest": {
"preset": "react-native",
@ -18,15 +19,12 @@
]
},
"dependencies": {
"@expo/vector-icons": "^10.0.0",
"@nartc/react-native-barcode-mask": "^1.1.9",
"@react-native-community/masked-view": "0.1.6",
"@react-navigation/bottom-tabs": "^5.1.1",
"@react-navigation/drawer": "^5.1.1",
"@react-navigation/native": "^5.0.9",
"@react-navigation/stack": "^5.1.1",
"expo": "^37.0.0",
"expo-barcode-scanner": "~8.1.0",
"expo-camera": "latest",
"i18n-js": "^3.3.0",
"react": "~16.9.0",
"react-dom": "16.9.0",
@ -36,6 +34,7 @@
"react-native-appearance": "~0.3.3",
"react-native-autolink": "^3.0.0",
"react-native-calendars": "^1.260.0",
"react-native-camera": "^3.23.1",
"react-native-collapsible": "^1.5.2",
"react-native-gesture-handler": "~1.6.0",
"react-native-image-modal": "^1.0.6",
@ -50,22 +49,21 @@
"react-native-safe-area-context": "0.7.3",
"react-native-screens": "~2.2.0",
"react-native-splash-screen": "^3.2.0",
"react-native-unimodules": "~0.9.0",
"react-native-vector-icons": "^6.6.0",
"react-native-web": "~0.11.7",
"react-native-webview": "8.1.1",
"react-navigation-collapsible": "^5.5.0",
"react-navigation-header-buttons": "^3.0.5"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"babel-jest": "~25.2.6",
"jest": "^25.1.0",
"react-test-renderer": "^16.13.1",
"@babel/cli": "^7.8.4",
"@babel/preset-flow": "^7.9.0",
"babel-preset-expo": "^8.1.0",
"flow-bin": "^0.122.0",
"jest-extended": "^0.11.5"
},
"private": true
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@react-native-community/eslint-config": "^0.0.5",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"jest": "^24.9.0",
"metro-react-native-babel-preset": "^0.58.0",
"react-test-renderer": "16.9.0",
"flow-bin": "^0.122.0"
}
}

View file

@ -12,8 +12,7 @@ type Props = {
title: string,
subtitle?: string,
left?: (props: { [keys: string]: any }) => React.Node,
startOpen: boolean,
keepOpen: boolean,
opened: boolean,
unmountWhenCollapsed: boolean,
children?: React.Node,
}
@ -24,36 +23,51 @@ type State = {
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
class AnimatedAccordion extends React.PureComponent<Props, State> {
class AnimatedAccordion extends React.Component<Props, State> {
static defaultProps = {
startOpen: false,
keepOpen: false,
opened: false,
unmountWhenCollapsed: false,
}
chevronRef: { current: null | AnimatedListIcon };
chevronIcon: string;
animStart: string;
animEnd: string;
state = {
expanded: false,
expanded: this.props.opened,
}
constructor(props) {
super(props);
this.chevronRef = React.createRef();
this.setupChevron();
}
componentDidMount() {
if (this.props.startOpen)
this.toggleAccordion();
setupChevron() {
if (this.state.expanded) {
this.chevronIcon = "chevron-up";
this.animStart = "180deg";
this.animEnd = "0deg";
} else {
this.chevronIcon = "chevron-down";
this.animStart = "0deg";
this.animEnd = "180deg";
}
}
toggleAccordion = () => {
if (!this.props.keepOpen) {
if (this.chevronRef.current != null)
this.chevronRef.current.transitionTo({rotate: this.state.expanded ? '0deg' : '180deg'});
this.setState({expanded: !this.state.expanded})
}
if (this.chevronRef.current != null)
this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd});
this.setState({expanded: !this.state.expanded})
};
shouldComponentUpdate(nextProps: Props) {
this.state.expanded = nextProps.opened;
this.setupChevron();
return true;
}
render() {
const colors = this.props.theme.colors;
return (
@ -67,13 +81,13 @@ class AnimatedAccordion extends React.PureComponent<Props, State> {
right={(props) => <AnimatedListIcon
ref={this.chevronRef}
{...props}
icon={"chevron-down"}
icon={this.chevronIcon}
color={this.state.expanded ? colors.primary : undefined}
useNativeDriver
/>}
left={this.props.left}
/>
<Collapsible collapsed={!this.props.keepOpen && !this.state.expanded}>
<Collapsible collapsed={!this.state.expanded}>
{!this.props.unmountWhenCollapsed || (this.props.unmountWhenCollapsed && this.state.expanded)
? this.props.children
: null}

View file

@ -1,22 +1,43 @@
// @flow
import * as React from 'react';
import {Card, List, Text} from 'react-native-paper';
import {Card, Chip, List, Text} from 'react-native-paper';
import {StyleSheet, View} from "react-native";
import i18n from 'i18n-js';
import AnimatedAccordion from "../../Animations/AnimatedAccordion";
import {isItemInCategoryFilter} from "../../../utils/Search";
import type {category} from "../../../screens/Amicale/Clubs/ClubListScreen";
type Props = {
categoryRender: Function,
categories: Array<Object>,
categories: Array<category>,
onChipSelect: (id: number) => void,
selectedCategories: Array<number>,
}
class ClubListHeader extends React.Component<Props> {
shouldComponentUpdate(nextProps: Props) {
return nextProps.selectedCategories.length !== this.props.selectedCategories.length;
}
getChipRender = (category: category, key: string) => {
const onPress = () => this.props.onChipSelect(category.id);
return <Chip
selected={isItemInCategoryFilter(this.props.selectedCategories, [category.id])}
mode={'outlined'}
onPress={onPress}
style={{marginRight: 5, marginBottom: 5}}
key={key}
>
{category.name}
</Chip>;
};
getCategoriesRender() {
let final = [];
for (let i = 0; i < this.props.categories.length; i++) {
final.push(this.props.categoryRender(this.props.categories[i], this.props.categories[i].id));
final.push(this.getChipRender(this.props.categories[i], this.props.categories[i].id.toString()));
}
return final;
}
@ -27,7 +48,7 @@ class ClubListHeader extends React.Component<Props> {
<AnimatedAccordion
title={i18n.t("clubs.categories")}
left={props => <List.Icon {...props} icon="star"/>}
startOpen={true}
opened={true}
>
<Text style={styles.text}>{i18n.t("clubs.categoriesFilterMessage")}</Text>
<View style={styles.chipContainer}>

View file

@ -19,27 +19,16 @@ type Props = {
theme: CustomTheme,
}
type State = {
expanded: boolean,
}
const LIST_ITEM_HEIGHT = 64;
class GroupListAccordion extends React.Component<Props, State> {
class GroupListAccordion extends React.Component<Props> {
constructor(props) {
super(props);
this.state = {
expanded: props.item.id === "0",
}
}
shouldComponentUpdate(nextProps: Props, nextSate: State) {
if (nextProps.currentSearchString !== this.props.currentSearchString)
this.state.expanded = nextProps.currentSearchString.length > 0;
shouldComponentUpdate(nextProps: Props) {
return (nextProps.currentSearchString !== this.props.currentSearchString)
|| (nextSate.expanded !== this.state.expanded)
|| (nextProps.favoriteNumber !== this.props.favoriteNumber)
|| (nextProps.item.content.length !== this.props.item.content.length);
}
@ -61,8 +50,6 @@ class GroupListAccordion extends React.Component<Props, State> {
return null;
}
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
render() {
const item = this.props.item;
return (
@ -82,6 +69,7 @@ class GroupListAccordion extends React.Component<Props, State> {
/>
: null}
unmountWhenCollapsed={true}// Only render list if expanded for increased performance
opened={this.props.item.id === 0 || this.props.currentSearchString.length > 0}
>
{/*$FlowFixMe*/}
<FlatList
@ -91,8 +79,8 @@ class GroupListAccordion extends React.Component<Props, State> {
keyExtractor={this.keyExtractor}
listKey={item.id.toString()}
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
getItemLayout={this.itemLayout} // Broken with search
removeClippedSubviews={true}
// getItemLayout={this.itemLayout} // Broken with search
// removeClippedSubviews={true}
/>
</AnimatedAccordion>
</View>

View file

@ -1,7 +1,7 @@
// @flow
import * as React from 'react';
import {MaterialCommunityIcons} from "@expo/vector-icons";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import {HeaderButton, HeaderButtons} from 'react-navigation-header-buttons';
import {withTheme} from "react-native-paper";
import * as Touchable from "react-native/Libraries/Components/Touchable/TouchableNativeFeedback.android";

View file

@ -2,7 +2,7 @@
import * as React from 'react';
import {Image, Platform, StatusBar, StyleSheet, View} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import {Text} from "react-native-paper";
import i18n from 'i18n-js';
import AppIntroSlider from "react-native-app-intro-slider";

View file

@ -3,7 +3,7 @@
import * as React from 'react';
import {Button, Subheading, withTheme} from 'react-native-paper';
import {StyleSheet, View} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import i18n from 'i18n-js';
import {ERROR_TYPE} from "../../utils/WebData";
import * as Animatable from 'react-native-animatable';

View file

@ -3,7 +3,7 @@
import * as React from 'react';
import {View} from "react-native";
import {TouchableRipple, withTheme} from 'react-native-paper';
import {MaterialCommunityIcons} from "@expo/vector-icons";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import * as Animatable from "react-native-animatable";
type Props = {

View file

@ -23,13 +23,15 @@ import ServicesSectionScreen from "../screens/Services/ServicesSectionScreen";
import AmicaleContactScreen from "../screens/Amicale/AmicaleContactScreen";
import {createScreenCollapsibleStack, getWebsiteStack} from "../utils/CollapsibleUtils";
const modalTransition = Platform.OS === 'ios' ? TransitionPresets.ModalPresentationIOS : TransitionPresets.ModalSlideFromBottomIOS;
const defaultScreenOptions = {
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.ScaleFromCenterAndroid,
...modalTransition,
};
const modalTransition = Platform.OS === 'ios' ? TransitionPresets.ModalPresentationIOS : TransitionPresets.ModalSlideFromBottomIOS;
const ServicesStack = createStackNavigator();
@ -42,7 +44,7 @@ function ServicesStackComponent() {
>
{createScreenCollapsibleStack("index", ServicesStack, WebsitesHomeScreen, i18n.t('screens.services'))}
{createScreenCollapsibleStack("services-section", ServicesStack, ServicesSectionScreen, "SECTION")}
{createScreenCollapsibleStack("amicale-contact", ServicesStack, AmicaleContactScreen, i18n.t('screens.amicaleAbout'), true, {...modalTransition})}
{createScreenCollapsibleStack("amicale-contact", ServicesStack, AmicaleContactScreen, i18n.t('screens.amicaleAbout'))}
</ServicesStack.Navigator>
);
}
@ -60,10 +62,7 @@ function ProxiwashStackComponent() {
<ProxiwashStack.Screen
name="proxiwash-about"
component={ProxiwashAboutScreen}
options={{
title: i18n.t('screens.proxiwash'),
...modalTransition,
}}
options={{title: i18n.t('screens.proxiwash'),}}
/>
</ProxiwashStack.Navigator>
);
@ -79,19 +78,14 @@ function PlanningStackComponent() {
screenOptions={defaultScreenOptions}
>
<PlanningStack.Screen
name="planning"
name="index"
component={PlanningScreen}
options={{
title: i18n.t('screens.planning'),
}}
options={{title: i18n.t('screens.planning'),}}
/>
<PlanningStack.Screen
name="planning-information"
component={PlanningDisplayScreen}
options={{
title: i18n.t('screens.planningDisplayScreen'),
...modalTransition,
}}
options={{title: i18n.t('screens.planningDisplayScreen'),}}
/>
</PlanningStack.Navigator>
);
@ -130,34 +124,22 @@ function HomeStackComponent(initialRoute: string | null, defaultData: { [key: st
<HomeStack.Screen
name="scanner"
component={ScannerScreen}
options={{
title: i18n.t('screens.scanner'),
...modalTransition,
}}
options={{title: i18n.t('screens.scanner'),}}
/>
<HomeStack.Screen
name="club-information"
component={ClubDisplayScreen}
options={{
title: i18n.t('screens.clubDisplayScreen'),
...modalTransition,
}}
options={{title: i18n.t('screens.clubDisplayScreen'),}}
/>
<HomeStack.Screen
name="feed-information"
component={FeedItemScreen}
options={{
title: i18n.t('screens.feedDisplayScreen'),
...modalTransition,
}}
options={{title: i18n.t('screens.feedDisplayScreen'),}}
/>
<HomeStack.Screen
name="planning-information"
component={PlanningDisplayScreen}
options={{
title: i18n.t('screens.planningDisplayScreen'),
...modalTransition,
}}
options={{title: i18n.t('screens.planningDisplayScreen'),}}
/>
</HomeStack.Navigator>
);
@ -173,13 +155,7 @@ function PlanexStackComponent() {
screenOptions={defaultScreenOptions}
>
{getWebsiteStack("index", PlanexStack, PlanexScreen, "Planex")}
{createScreenCollapsibleStack(
"group-select",
PlanexStack,
GroupSelectionScreen,
"GROUP SELECT",
true,
{...modalTransition})}
{createScreenCollapsibleStack("group-select", PlanexStack, GroupSelectionScreen, "GROUP SELECT")}
</PlanexStack.Navigator>
);
}

View file

@ -2,7 +2,7 @@
import * as React from 'react';
import {Animated, Platform} from "react-native";
import {Chip, Searchbar} from 'react-native-paper';
import {Searchbar} from 'react-native-paper';
import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen";
import i18n from "i18n-js";
import ClubListItem from "../../../components/Lists/Clubs/ClubListItem";
@ -36,7 +36,7 @@ type Props = {
}
type State = {
currentlySelectedCategories: Array<string>,
currentlySelectedCategories: Array<number>,
currentSearchString: string,
}
@ -99,13 +99,11 @@ class ClubListScreen extends React.Component<Props, State> {
this.updateFilteredData(str, null);
};
keyExtractor = (item: club) => {
return item.id.toString();
};
keyExtractor = (item: club) => item.id.toString();
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
getScreen = (data: Array<{categories: Array<category>, clubs: Array<club>} | null>) => {
getScreen = (data: Array<{ categories: Array<category>, clubs: Array<club> } | null>) => {
let categoryList = [];
let clubList = [];
if (data[0] != null) {
@ -131,11 +129,9 @@ class ClubListScreen extends React.Component<Props, State> {
)
};
onChipSelect(id: string) {
this.updateFilteredData(null, id);
}
onChipSelect = (id: number) => this.updateFilteredData(null, id);
updateFilteredData(filterStr: string | null, categoryId: string | null) {
updateFilteredData(filterStr: string | null, categoryId: number | null) {
let newCategoriesState = [...this.state.currentlySelectedCategories];
let newStrState = this.state.currentSearchString;
if (filterStr !== null)
@ -154,23 +150,11 @@ class ClubListScreen extends React.Component<Props, State> {
})
}
getChipRender = (category: category, key: string) => {
const onPress = this.onChipSelect.bind(this, category.id);
return <Chip
selected={isItemInCategoryFilter(this.state.currentlySelectedCategories, [category.id])}
mode={'outlined'}
onPress={onPress}
style={{marginRight: 5, marginBottom: 5}}
key={key}
>
{category.name}
</Chip>;
};
getListHeader() {
return <ClubListHeader
categories={this.categories}
categoryRender={this.getChipRender}
selectedCategories={this.state.currentlySelectedCategories}
onChipSelect={this.onChipSelect}
/>;
}
@ -189,7 +173,7 @@ class ClubListScreen extends React.Component<Props, State> {
return shouldRender;
}
getRenderItem = ({item}: {item: club}) => {
getRenderItem = ({item}: { item: club }) => {
const onPress = this.onListItemPress.bind(this, item);
if (this.shouldRenderItem(item)) {
return (

View file

@ -1,15 +1,16 @@
// @flow
import * as React from 'react';
import {Linking, StyleSheet, View} from "react-native";
import {Linking, Platform, StyleSheet, View} from "react-native";
import {Button, Text, withTheme} from 'react-native-paper';
import {BarCodeScanner} from "expo-barcode-scanner";
import {Camera} from 'expo-camera';
import {RNCamera} from 'react-native-camera';
import {BarcodeMask} from '@nartc/react-native-barcode-mask';
import URLHandler from "../../utils/URLHandler";
import AlertDialog from "../../components/Dialogs/AlertDialog";
import i18n from 'i18n-js';
import CustomTabBar from "../../components/Tabbar/CustomTabBar";
import LoadingConfirmDialog from "../../components/Dialogs/LoadingConfirmDialog";
import {PERMISSIONS, request, RESULTS} from 'react-native-permissions';
type Props = {};
type State = {
@ -40,9 +41,14 @@ class ScannerScreen extends React.Component<Props, State> {
this.requestPermissions();
}
requestPermissions = () => Camera.requestPermissionsAsync().then(this.updatePermissionStatus);
requestPermissions = () => {
if (Platform.OS === 'android')
request(PERMISSIONS.ANDROID.CAMERA).then(this.updatePermissionStatus)
else
request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus)
};
updatePermissionStatus = ({status}) => this.setState({hasPermission: status === "granted"});
updatePermissionStatus = (result) => this.setState({hasPermission: result === RESULTS.GRANTED});
handleCodeScanned = ({type, data}) => {
if (!URLHandler.isUrlValid(data))
@ -71,36 +77,6 @@ class ScannerScreen extends React.Component<Props, State> {
</View>
}
getOverlay() {
return (
<View style={{flex: 1}}>
<View style={{flex: 1}}>
<View style={{...overlayBackground, top: 0, height: '10%', width: '80%', left: '10%'}}/>
<View style={{...overlayBackground, left: 0, width: '10%', height: '100%'}}/>
<View style={{...overlayBackground, right: 0, width: '10%', height: '100%'}}/>
<View style={{...overlayBackground, bottom: 0, height: '10%', width: '80%', left: '10%'}}/>
</View>
<View style={styles.overlayTopLeft}>
<View style={{...overlayHorizontalLineStyle, top: 0}}/>
<View style={{...overlayVerticalLineStyle, left: 0}}/>
</View>
<View style={styles.overlayTopRight}>
<View style={{...overlayHorizontalLineStyle, top: 0}}/>
<View style={{...overlayVerticalLineStyle, right: 0}}/>
</View>
<View style={styles.overlayBottomLeft}>
<View style={{...overlayHorizontalLineStyle, bottom: 0}}/>
<View style={{...overlayVerticalLineStyle, left: 0}}/>
</View>
<View style={styles.overlayBottomRight}>
<View style={{...overlayHorizontalLineStyle, bottom: 0}}/>
<View style={{...overlayVerticalLineStyle, right: 0}}/>
</View>
</View>
);
}
showHelpDialog = () => {
this.setState({
dialogVisible: true,
@ -133,19 +109,22 @@ class ScannerScreen extends React.Component<Props, State> {
getScanner() {
return (
<View style={styles.cameraContainer}>
<Camera
onBarCodeScanned={this.state.scanned ? undefined : this.handleCodeScanned}
type={Camera.Constants.Type.back}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
style={StyleSheet.absoluteFill}
ratio={'1:1'}
>
{this.getOverlay()}
</Camera>
</View>
<RNCamera
onBarCodeRead={this.state.scanned ? undefined : this.handleCodeScanned}
type={RNCamera.Constants.Type.back}
barCodeScannerSettings={{
barCodeTypes: [RNCamera.Constants.BarCodeType.qr],
}}
style={StyleSheet.absoluteFill}
captureAudio={false}
>
<BarcodeMask
backgroundColor={"#000"}
maskOpacity={0.5}
animatedLineThickness={1}
animationDuration={1000}
/>
</RNCamera>
);
}
@ -153,22 +132,20 @@ class ScannerScreen extends React.Component<Props, State> {
return (
<View style={{
...styles.container,
marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
marginBottom: CustomTabBar.TAB_BAR_HEIGHT
}}>
{this.state.hasPermission
? this.getScanner()
: this.getPermissionScreen()
}
<View style={{height: 50}}>
<Button
icon="information"
mode="contained"
onPress={this.showHelpDialog}
style={styles.button}
>
{i18n.t("scannerScreen.helpButton")}
</Button>
</View>
{this.state.hasPermission
? this.getScanner()
: this.getPermissionScreen()
}
<Button
icon="information"
mode="contained"
onPress={this.showHelpDialog}
style={styles.button}
>
{i18n.t("scannerScreen.helpButton")}
</Button>
<AlertDialog
visible={this.state.dialogVisible}
onDismiss={this.onDialogDismiss}
@ -185,74 +162,17 @@ class ScannerScreen extends React.Component<Props, State> {
}
}
const borderOffset = '10%';
const overlayBoxStyle = {
position: 'absolute',
width: 25,
height: 25,
};
const overlayLineStyle = {
position: 'absolute',
backgroundColor: "#fff",
borderRadius: 2,
};
const overlayHorizontalLineStyle = {
...overlayLineStyle,
width: '100%',
height: 5,
};
const overlayVerticalLineStyle = {
...overlayLineStyle,
height: '100%',
width: 5,
};
const overlayBackground = {
backgroundColor: "rgba(0,0,0,0.47)",
position: "absolute",
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
cameraContainer: {
marginTop: 'auto',
marginBottom: 'auto',
aspectRatio: 1,
width: '100%',
},
button: {
position: 'absolute',
bottom: 5,
bottom: 20,
width: '80%',
left: '10%'
},
overlayTopLeft: {
...overlayBoxStyle,
top: borderOffset,
left: borderOffset,
},
overlayTopRight: {
...overlayBoxStyle,
top: borderOffset,
right: borderOffset,
},
overlayBottomLeft: {
...overlayBoxStyle,
bottom: borderOffset,
left: borderOffset,
},
overlayBottomRight: {
...overlayBoxStyle,
bottom: borderOffset,
right: borderOffset,
},
});
export default withTheme(ScannerScreen);

View file

@ -36,7 +36,6 @@ class FeedbackScreen extends React.Component<Props> {
}}>
<Button
icon="email"
mode="contained"
style={{
marginLeft: 'auto',
marginTop: 5,
@ -46,7 +45,6 @@ class FeedbackScreen extends React.Component<Props> {
</Button>
<Button
icon="git"
mode="contained"
style={{
marginLeft: 'auto',
marginTop: 5,
@ -56,7 +54,6 @@ class FeedbackScreen extends React.Component<Props> {
</Button>
<Button
icon="facebook"
mode="contained"
style={{
marginLeft: 'auto',
marginTop: 5,

View file

@ -1,12 +1,12 @@
// @flow
import * as React from 'react';
import {Alert, Platform, View} from 'react-native';
import {Alert, View} from 'react-native';
import i18n from "i18n-js";
import WebSectionList from "../../components/Screens/WebSectionList";
import * as Notifications from "../../utils/Notifications";
import AsyncStorageManager from "../../managers/AsyncStorageManager";
import * as Expo from "expo";
// import * as Expo from "expo";
import {Avatar, Banner, Button, Card, Text, withTheme} from 'react-native-paper';
import ProxiwashListItem from "../../components/Lists/Proxiwash/ProxiwashListItem";
import ProxiwashConstants from "../../constants/ProxiwashConstants";
@ -92,18 +92,18 @@ class ProxiwashScreen extends React.Component<Props, State> {
this.setState({machinesWatched: fetchedList})
});
// Get updated watchlist after received notification
Expo.Notifications.addListener(() => {
Notifications.getMachineNotificationWatchlist((fetchedList) => {
this.setState({machinesWatched: fetchedList})
});
});
if (Platform.OS === 'android') {
Expo.Notifications.createChannelAndroidAsync('reminders', {
name: 'Reminders',
priority: 'max',
vibrate: [0, 250, 250, 250],
});
}
// Expo.Notifications.addListener(() => {
// Notifications.getMachineNotificationWatchlist((fetchedList) => {
// this.setState({machinesWatched: fetchedList})
// });
// });
// if (Platform.OS === 'android') {
// Expo.Notifications.createChannelAndroidAsync('reminders', {
// name: 'Reminders',
// priority: 'max',
// vibrate: [0, 250, 250, 250],
// });
// }
}
}

View file

@ -61,7 +61,7 @@ class ProximoListScreen extends React.Component<Props, State> {
constructor(props) {
super(props);
this.listData = this.props.route.params['data']['data'];
this.listData = this.props.route.params['data']['data'].sort(sortName);
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
this.state = {
currentSearchString: '',

View file

@ -3,7 +3,7 @@
import * as React from 'react';
import {Alert, View} from 'react-native';
import {IconButton, Text, withTheme} from 'react-native-paper';
import {MaterialCommunityIcons} from "@expo/vector-icons";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import GameLogic from "./GameLogic";
import Grid from "./components/Grid";
import Preview from "./components/Preview";

View file

@ -1,7 +1,7 @@
// @flow
import {checkNotifications, requestNotifications, RESULTS} from 'react-native-permissions';
import {Notifications} from 'expo';
// import {Notifications} from 'expo';
import AsyncStorageManager from "../managers/AsyncStorageManager";
import LocaleManager from "../managers/LocaleManager";
import passwords from "../../passwords";
@ -40,15 +40,15 @@ export async function askPermissions() {
* @return {Promise<void>}
*/
export async function initExpoToken() {
let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
if (token === '') {
askPermissions().then(() => {
Notifications.getExpoPushTokenAsync().then((token) => {
// Save token for instant use later on
AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.expoToken.key, token);
});
});
}
// let token = AsyncStorageManager.getInstance().preferences.expoToken.current;
// if (token === '') {
// askPermissions().then(() => {
// Notifications.getExpoPushTokenAsync().then((token) => {
// // Save token for instant use later on
// AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.expoToken.key, token);
// });
// });
// }
}
/**