Compare commits
No commits in common. "a4bbd841367ce2fc7609993c103e821ad466ca60" and "1e0cc867b8bb96db2e7a05821fb6e3439ac2627d" have entirely different histories.
a4bbd84136
...
1e0cc867b8
25 changed files with 335 additions and 202 deletions
|
|
@ -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,7 +134,6 @@ android {
|
|||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 16
|
||||
versionName "2.0.0"
|
||||
missingDimensionStrategy 'react-native-camera', 'general'
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
|
|
@ -191,6 +190,7 @@ 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/";
|
||||
|
|
|
|||
|
|
@ -9,6 +9,16 @@ 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;
|
||||
|
|
@ -16,6 +26,10 @@ 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
|
||||
|
|
@ -26,6 +40,7 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['babel-preset-expo', '@babel/preset-flow'],
|
||||
env: {
|
||||
production: {
|
||||
plugins: ['react-native-paper/babel'],
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
8
index.js
8
index.js
|
|
@ -1,4 +1,8 @@
|
|||
import {AppRegistry} from 'react-native';
|
||||
import {registerRootComponent} from 'expo';
|
||||
|
||||
import App from './App';
|
||||
|
||||
AppRegistry.registerComponent('main', () => 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);
|
||||
|
|
|
|||
|
|
@ -71,9 +71,5 @@
|
|||
<string>Automatic</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>MaterialCommunityIcons.ttf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,4 @@ 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
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* Metro configuration for React Native
|
||||
* https://github.com/facebook/react-native
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
transformer: {
|
||||
getTransformOptions: async () => ({
|
||||
transform: {
|
||||
experimentalImportSupport: false,
|
||||
inlineRequires: false,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
36
package.json
36
package.json
|
|
@ -1,13 +1,12 @@
|
|||
{
|
||||
"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",
|
||||
"lint": "eslint ."
|
||||
"testw": "jest --watch",
|
||||
"testc": "jest --coverage"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
|
|
@ -19,12 +18,15 @@
|
|||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@nartc/react-native-barcode-mask": "^1.1.9",
|
||||
"@expo/vector-icons": "^10.0.0",
|
||||
"@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",
|
||||
|
|
@ -34,7 +36,6 @@
|
|||
"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",
|
||||
|
|
@ -49,21 +50,22 @@
|
|||
"react-native-safe-area-context": "0.7.3",
|
||||
"react-native-screens": "~2.2.0",
|
||||
"react-native-splash-screen": "^3.2.0",
|
||||
"react-native-vector-icons": "^6.6.0",
|
||||
"react-native-unimodules": "~0.9.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.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"
|
||||
}
|
||||
"@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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ type Props = {
|
|||
title: string,
|
||||
subtitle?: string,
|
||||
left?: (props: { [keys: string]: any }) => React.Node,
|
||||
opened: boolean,
|
||||
startOpen: boolean,
|
||||
keepOpen: boolean,
|
||||
unmountWhenCollapsed: boolean,
|
||||
children?: React.Node,
|
||||
}
|
||||
|
|
@ -23,51 +24,36 @@ type State = {
|
|||
|
||||
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
||||
|
||||
class AnimatedAccordion extends React.Component<Props, State> {
|
||||
class AnimatedAccordion extends React.PureComponent<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
opened: false,
|
||||
startOpen: false,
|
||||
keepOpen: false,
|
||||
unmountWhenCollapsed: false,
|
||||
}
|
||||
chevronRef: { current: null | AnimatedListIcon };
|
||||
chevronIcon: string;
|
||||
animStart: string;
|
||||
animEnd: string;
|
||||
|
||||
state = {
|
||||
expanded: this.props.opened,
|
||||
expanded: false,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.chevronRef = React.createRef();
|
||||
this.setupChevron();
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.props.startOpen)
|
||||
this.toggleAccordion();
|
||||
}
|
||||
|
||||
toggleAccordion = () => {
|
||||
if (this.chevronRef.current != null)
|
||||
this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd});
|
||||
this.setState({expanded: !this.state.expanded})
|
||||
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})
|
||||
}
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
this.state.expanded = nextProps.opened;
|
||||
this.setupChevron();
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const colors = this.props.theme.colors;
|
||||
return (
|
||||
|
|
@ -81,13 +67,13 @@ class AnimatedAccordion extends React.Component<Props, State> {
|
|||
right={(props) => <AnimatedListIcon
|
||||
ref={this.chevronRef}
|
||||
{...props}
|
||||
icon={this.chevronIcon}
|
||||
icon={"chevron-down"}
|
||||
color={this.state.expanded ? colors.primary : undefined}
|
||||
useNativeDriver
|
||||
/>}
|
||||
left={this.props.left}
|
||||
/>
|
||||
<Collapsible collapsed={!this.state.expanded}>
|
||||
<Collapsible collapsed={!this.props.keepOpen && !this.state.expanded}>
|
||||
{!this.props.unmountWhenCollapsed || (this.props.unmountWhenCollapsed && this.state.expanded)
|
||||
? this.props.children
|
||||
: null}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,22 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Card, Chip, List, Text} from 'react-native-paper';
|
||||
import {Card, 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 = {
|
||||
categories: Array<category>,
|
||||
onChipSelect: (id: number) => void,
|
||||
selectedCategories: Array<number>,
|
||||
categoryRender: Function,
|
||||
categories: Array<Object>,
|
||||
}
|
||||
|
||||
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.getChipRender(this.props.categories[i], this.props.categories[i].id.toString()));
|
||||
final.push(this.props.categoryRender(this.props.categories[i], this.props.categories[i].id));
|
||||
}
|
||||
return final;
|
||||
}
|
||||
|
|
@ -48,7 +27,7 @@ class ClubListHeader extends React.Component<Props> {
|
|||
<AnimatedAccordion
|
||||
title={i18n.t("clubs.categories")}
|
||||
left={props => <List.Icon {...props} icon="star"/>}
|
||||
opened={true}
|
||||
startOpen={true}
|
||||
>
|
||||
<Text style={styles.text}>{i18n.t("clubs.categoriesFilterMessage")}</Text>
|
||||
<View style={styles.chipContainer}>
|
||||
|
|
|
|||
|
|
@ -19,16 +19,27 @@ type Props = {
|
|||
theme: CustomTheme,
|
||||
}
|
||||
|
||||
type State = {
|
||||
expanded: boolean,
|
||||
}
|
||||
|
||||
const LIST_ITEM_HEIGHT = 64;
|
||||
|
||||
class GroupListAccordion extends React.Component<Props> {
|
||||
class GroupListAccordion extends React.Component<Props, State> {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
expanded: props.item.id === "0",
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
shouldComponentUpdate(nextProps: Props, nextSate: State) {
|
||||
if (nextProps.currentSearchString !== this.props.currentSearchString)
|
||||
this.state.expanded = nextProps.currentSearchString.length > 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -50,6 +61,8 @@ class GroupListAccordion extends React.Component<Props> {
|
|||
return null;
|
||||
}
|
||||
|
||||
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
|
||||
|
||||
render() {
|
||||
const item = this.props.item;
|
||||
return (
|
||||
|
|
@ -69,7 +82,6 @@ class GroupListAccordion extends React.Component<Props> {
|
|||
/>
|
||||
: null}
|
||||
unmountWhenCollapsed={true}// Only render list if expanded for increased performance
|
||||
opened={this.props.item.id === 0 || this.props.currentSearchString.length > 0}
|
||||
>
|
||||
{/*$FlowFixMe*/}
|
||||
<FlatList
|
||||
|
|
@ -79,8 +91,8 @@ class GroupListAccordion extends React.Component<Props> {
|
|||
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>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import {Image, Platform, StatusBar, StyleSheet, View} from "react-native";
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import {Text} from "react-native-paper";
|
||||
import i18n from 'i18n-js';
|
||||
import AppIntroSlider from "react-native-app-intro-slider";
|
||||
|
|
|
|||
|
|
@ -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 "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import i18n from 'i18n-js';
|
||||
import {ERROR_TYPE} from "../../utils/WebData";
|
||||
import * as Animatable from 'react-native-animatable';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from 'react';
|
||||
import {View} from "react-native";
|
||||
import {TouchableRipple, withTheme} from 'react-native-paper';
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import * as Animatable from "react-native-animatable";
|
||||
|
||||
type Props = {
|
||||
|
|
|
|||
|
|
@ -23,15 +23,13 @@ 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,
|
||||
...modalTransition,
|
||||
...TransitionPresets.ScaleFromCenterAndroid,
|
||||
};
|
||||
|
||||
const modalTransition = Platform.OS === 'ios' ? TransitionPresets.ModalPresentationIOS : TransitionPresets.ModalSlideFromBottomIOS;
|
||||
|
||||
const ServicesStack = createStackNavigator();
|
||||
|
||||
|
|
@ -44,7 +42,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'))}
|
||||
{createScreenCollapsibleStack("amicale-contact", ServicesStack, AmicaleContactScreen, i18n.t('screens.amicaleAbout'), true, {...modalTransition})}
|
||||
</ServicesStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
@ -62,7 +60,10 @@ function ProxiwashStackComponent() {
|
|||
<ProxiwashStack.Screen
|
||||
name="proxiwash-about"
|
||||
component={ProxiwashAboutScreen}
|
||||
options={{title: i18n.t('screens.proxiwash'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.proxiwash'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
</ProxiwashStack.Navigator>
|
||||
);
|
||||
|
|
@ -78,14 +79,19 @@ function PlanningStackComponent() {
|
|||
screenOptions={defaultScreenOptions}
|
||||
>
|
||||
<PlanningStack.Screen
|
||||
name="index"
|
||||
name="planning"
|
||||
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'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.planningDisplayScreen'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
</PlanningStack.Navigator>
|
||||
);
|
||||
|
|
@ -124,22 +130,34 @@ function HomeStackComponent(initialRoute: string | null, defaultData: { [key: st
|
|||
<HomeStack.Screen
|
||||
name="scanner"
|
||||
component={ScannerScreen}
|
||||
options={{title: i18n.t('screens.scanner'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.scanner'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
<HomeStack.Screen
|
||||
name="club-information"
|
||||
component={ClubDisplayScreen}
|
||||
options={{title: i18n.t('screens.clubDisplayScreen'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.clubDisplayScreen'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
<HomeStack.Screen
|
||||
name="feed-information"
|
||||
component={FeedItemScreen}
|
||||
options={{title: i18n.t('screens.feedDisplayScreen'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.feedDisplayScreen'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
<HomeStack.Screen
|
||||
name="planning-information"
|
||||
component={PlanningDisplayScreen}
|
||||
options={{title: i18n.t('screens.planningDisplayScreen'),}}
|
||||
options={{
|
||||
title: i18n.t('screens.planningDisplayScreen'),
|
||||
...modalTransition,
|
||||
}}
|
||||
/>
|
||||
</HomeStack.Navigator>
|
||||
);
|
||||
|
|
@ -155,7 +173,13 @@ function PlanexStackComponent() {
|
|||
screenOptions={defaultScreenOptions}
|
||||
>
|
||||
{getWebsiteStack("index", PlanexStack, PlanexScreen, "Planex")}
|
||||
{createScreenCollapsibleStack("group-select", PlanexStack, GroupSelectionScreen, "GROUP SELECT")}
|
||||
{createScreenCollapsibleStack(
|
||||
"group-select",
|
||||
PlanexStack,
|
||||
GroupSelectionScreen,
|
||||
"GROUP SELECT",
|
||||
true,
|
||||
{...modalTransition})}
|
||||
</PlanexStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import {Animated, Platform} from "react-native";
|
||||
import {Searchbar} from 'react-native-paper';
|
||||
import {Chip, 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<number>,
|
||||
currentlySelectedCategories: Array<string>,
|
||||
currentSearchString: string,
|
||||
}
|
||||
|
||||
|
|
@ -99,11 +99,13 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
this.updateFilteredData(str, null);
|
||||
};
|
||||
|
||||
keyExtractor = (item: club) => item.id.toString();
|
||||
keyExtractor = (item: club) => {
|
||||
return 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) {
|
||||
|
|
@ -129,9 +131,11 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
)
|
||||
};
|
||||
|
||||
onChipSelect = (id: number) => this.updateFilteredData(null, id);
|
||||
onChipSelect(id: string) {
|
||||
this.updateFilteredData(null, id);
|
||||
}
|
||||
|
||||
updateFilteredData(filterStr: string | null, categoryId: number | null) {
|
||||
updateFilteredData(filterStr: string | null, categoryId: string | null) {
|
||||
let newCategoriesState = [...this.state.currentlySelectedCategories];
|
||||
let newStrState = this.state.currentSearchString;
|
||||
if (filterStr !== null)
|
||||
|
|
@ -150,11 +154,23 @@ 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}
|
||||
selectedCategories={this.state.currentlySelectedCategories}
|
||||
onChipSelect={this.onChipSelect}
|
||||
categoryRender={this.getChipRender}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +189,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 (
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Linking, Platform, StyleSheet, View} from "react-native";
|
||||
import {Linking, StyleSheet, View} from "react-native";
|
||||
import {Button, Text, withTheme} from 'react-native-paper';
|
||||
import {RNCamera} from 'react-native-camera';
|
||||
import {BarcodeMask} from '@nartc/react-native-barcode-mask';
|
||||
import {BarCodeScanner} from "expo-barcode-scanner";
|
||||
import {Camera} from 'expo-camera';
|
||||
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 = {
|
||||
|
|
@ -41,14 +40,9 @@ class ScannerScreen extends React.Component<Props, State> {
|
|||
this.requestPermissions();
|
||||
}
|
||||
|
||||
requestPermissions = () => {
|
||||
if (Platform.OS === 'android')
|
||||
request(PERMISSIONS.ANDROID.CAMERA).then(this.updatePermissionStatus)
|
||||
else
|
||||
request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus)
|
||||
};
|
||||
requestPermissions = () => Camera.requestPermissionsAsync().then(this.updatePermissionStatus);
|
||||
|
||||
updatePermissionStatus = (result) => this.setState({hasPermission: result === RESULTS.GRANTED});
|
||||
updatePermissionStatus = ({status}) => this.setState({hasPermission: status === "granted"});
|
||||
|
||||
handleCodeScanned = ({type, data}) => {
|
||||
if (!URLHandler.isUrlValid(data))
|
||||
|
|
@ -77,6 +71,36 @@ 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,
|
||||
|
|
@ -109,22 +133,19 @@ class ScannerScreen extends React.Component<Props, State> {
|
|||
|
||||
getScanner() {
|
||||
return (
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -132,20 +153,22 @@ class ScannerScreen extends React.Component<Props, State> {
|
|||
return (
|
||||
<View style={{
|
||||
...styles.container,
|
||||
marginBottom: CustomTabBar.TAB_BAR_HEIGHT
|
||||
marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
|
||||
}}>
|
||||
{this.state.hasPermission
|
||||
? this.getScanner()
|
||||
: this.getPermissionScreen()
|
||||
}
|
||||
<Button
|
||||
icon="information"
|
||||
mode="contained"
|
||||
onPress={this.showHelpDialog}
|
||||
style={styles.button}
|
||||
>
|
||||
{i18n.t("scannerScreen.helpButton")}
|
||||
</Button>
|
||||
{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>
|
||||
<AlertDialog
|
||||
visible={this.state.dialogVisible}
|
||||
onDismiss={this.onDialogDismiss}
|
||||
|
|
@ -162,17 +185,74 @@ 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: 20,
|
||||
bottom: 5,
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
}}>
|
||||
<Button
|
||||
icon="email"
|
||||
mode="contained"
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
@ -45,6 +46,7 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
</Button>
|
||||
<Button
|
||||
icon="git"
|
||||
mode="contained"
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
@ -54,6 +56,7 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
</Button>
|
||||
<Button
|
||||
icon="facebook"
|
||||
mode="contained"
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Alert, View} from 'react-native';
|
||||
import {Alert, Platform, 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],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class ProximoListScreen extends React.Component<Props, State> {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.listData = this.props.route.params['data']['data'].sort(sortName);
|
||||
this.listData = this.props.route.params['data']['data'];
|
||||
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
|
||||
this.state = {
|
||||
currentSearchString: '',
|
||||
|
|
|
|||
|
|
@ -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 "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||
import GameLogic from "./GameLogic";
|
||||
import Grid from "./components/Grid";
|
||||
import Preview from "./components/Preview";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue