initial
This commit is contained in:
commit
b9cf44cc13
44 changed files with 19887 additions and 0 deletions
15
.eslintrc.js
Normal file
15
.eslintrc.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
plugins: [
|
||||||
|
"@typescript-eslint",
|
||||||
|
],
|
||||||
|
extends: [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
"indent": ["error", 2],
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
}
|
||||||
|
};
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
17
App.tsx
Normal file
17
App.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React from "react";
|
||||||
|
import { SafeAreaView, View, Text } from "react-native";
|
||||||
|
import Home from "./pages/Home";
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<SafeAreaView>
|
||||||
|
<View styles={{ backgroundColor: "#00ff00" }}>
|
||||||
|
<Text styles={{ color: "white" }}>Poggers Fish</Text>
|
||||||
|
|
||||||
|
<Home />
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
2
android/.gitignore
vendored
Normal file
2
android/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.gradle
|
||||||
|
app/build
|
36
android/app/build.gradle
Normal file
36
android/app/build.gradle
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
apply plugin: "com.android.application"
|
||||||
|
apply from: "../../node_modules/react-native/react.gradle"
|
||||||
|
|
||||||
|
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion = rootProject.ext.compileSdkVersion
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "io.mzhang.iqeats"
|
||||||
|
targetSdkVersion = rootProject.ext.targetSdkVersion
|
||||||
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
|
implementation "com.facebook.react:react-native:+"
|
||||||
|
|
||||||
|
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||||
|
exclude group:'com.facebook.fbjni'
|
||||||
|
}
|
||||||
|
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||||
|
exclude group:'com.facebook.flipper'
|
||||||
|
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||||
|
}
|
||||||
|
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
||||||
|
exclude group:'com.facebook.flipper'
|
||||||
|
}
|
||||||
|
|
||||||
|
implementation jscFlavor
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
17
android/app/src/main/AndroidManifest.xml
Normal file
17
android/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mzhang.iqeats">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<application
|
||||||
|
android:name=".MainApplication"
|
||||||
|
android:theme="@style/AppTheme"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
|
<!-- TODO: don't leave usesCleartextTraffic in -->
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
BIN
android/app/src/main/assets/fonts/AntDesign.ttf
Normal file
BIN
android/app/src/main/assets/fonts/AntDesign.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Entypo.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Entypo.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/EvilIcons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/EvilIcons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Feather.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Feather.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/FontAwesome.ttf
Normal file
BIN
android/app/src/main/assets/fonts/FontAwesome.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf
Normal file
BIN
android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf
Normal file
BIN
android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf
Normal file
BIN
android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Fontisto.ttf
Executable file
BIN
android/app/src/main/assets/fonts/Fontisto.ttf
Executable file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Foundation.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Foundation.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Ionicons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Ionicons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/MaterialIcons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/MaterialIcons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Octicons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Octicons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/SimpleLineIcons.ttf
Normal file
BIN
android/app/src/main/assets/fonts/SimpleLineIcons.ttf
Normal file
Binary file not shown.
BIN
android/app/src/main/assets/fonts/Zocial.ttf
Normal file
BIN
android/app/src/main/assets/fonts/Zocial.ttf
Normal file
Binary file not shown.
16
android/app/src/main/java/io/mzhang/iqeats/MainActivity.java
Normal file
16
android/app/src/main/java/io/mzhang/iqeats/MainActivity.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package io.mzhang.iqeats;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import com.facebook.react.ReactActivity;
|
||||||
|
|
||||||
|
public class MainActivity extends ReactActivity {
|
||||||
|
@Override
|
||||||
|
protected String getMainComponentName() {
|
||||||
|
return "iqeats";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package io.mzhang.iqeats;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import com.facebook.react.PackageList;
|
||||||
|
import com.facebook.react.ReactApplication;
|
||||||
|
import com.facebook.react.ReactInstanceManager;
|
||||||
|
import com.facebook.react.ReactNativeHost;
|
||||||
|
import com.facebook.react.ReactPackage;
|
||||||
|
import com.facebook.soloader.SoLoader;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MainApplication extends Application implements ReactApplication {
|
||||||
|
|
||||||
|
private final ReactNativeHost mReactNativeHost =
|
||||||
|
new ReactNativeHost(this) {
|
||||||
|
@Override
|
||||||
|
public boolean getUseDeveloperSupport() {
|
||||||
|
return BuildConfig.DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<ReactPackage> getPackages() {
|
||||||
|
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||||
|
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||||
|
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||||
|
// packages.add(new MyReactNativePackage());
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getJSMainModuleName() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReactNativeHost getReactNativeHost() {
|
||||||
|
return mReactNativeHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
SoLoader.init(this, /* native exopackage */ false);
|
||||||
|
// initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
|
||||||
|
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param reactInstanceManager
|
||||||
|
*/
|
||||||
|
private static void initializeFlipper(
|
||||||
|
Context context, ReactInstanceManager reactInstanceManager) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
We use reflection here to pick up the class that initializes Flipper,
|
||||||
|
since Flipper library is not available in release mode
|
||||||
|
*/
|
||||||
|
Class<?> aClass = Class.forName("io.mzhang.iqeats.ReactNativeFlipper");
|
||||||
|
aClass
|
||||||
|
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||||
|
.invoke(null, context, reactInstanceManager);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
android/app/src/main/res/values/strings.xml
Normal file
3
android/app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">iQeats</string>
|
||||||
|
</resources>
|
5
android/app/src/main/res/values/styles.xml
Normal file
5
android/app/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||||
|
<item name="android:textColor">#000000</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
27
android/build.gradle
Normal file
27
android/build.gradle
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
buildscript {
|
||||||
|
ext {
|
||||||
|
compileSdkVersion = 29
|
||||||
|
targetSdkVersion = 29
|
||||||
|
minSdkVersion = 21
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath("com.android.tools.build:gradle:4.1.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
maven { url("$rootDir/../node_modules/react-native/android") }
|
||||||
|
maven { url("$rootDir/../node_modules/jsc-android/dist") }
|
||||||
|
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url "https://www.jitpack.io" }
|
||||||
|
}
|
||||||
|
}
|
3
android/gradle.properties
Normal file
3
android/gradle.properties
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
FLIPPER_VERSION=0.75.1
|
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
185
android/gradlew
vendored
Executable file
185
android/gradlew
vendored
Executable file
|
@ -0,0 +1,185 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MSYS* | MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
89
android/gradlew.bat
vendored
Normal file
89
android/gradlew.bat
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
3
android/settings.gradle
Normal file
3
android/settings.gradle
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
rootProject.name = "iqeats"
|
||||||
|
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||||
|
include ":app"
|
4
app.json
Normal file
4
app.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "iqeats",
|
||||||
|
"displayName": "iQeats"
|
||||||
|
}
|
6
assets/data/demo.js
Normal file
6
assets/data/demo.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = [
|
||||||
|
{ name: "osu!" },
|
||||||
|
{ name: "Taco Bell" },
|
||||||
|
{ name: "McDonalds" },
|
||||||
|
{ name: "Five Guys" },
|
||||||
|
];
|
14
assets/styles/index.js
Normal file
14
assets/styles/index.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { StyleSheet, Dimensions } from "react-native";
|
||||||
|
|
||||||
|
const WHITE = "#FFFFFF";
|
||||||
|
|
||||||
|
const DIMENSION_WIDTH = Dimensions.get("window").width;
|
||||||
|
const DIMENSION_HEIGHT = Dimensions.get("window").height;
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
suggestionsCard: {
|
||||||
|
backgroundColor: WHITE,
|
||||||
|
margin: 10,
|
||||||
|
padding: 10,
|
||||||
|
}
|
||||||
|
});
|
30
components/Card.tsx
Normal file
30
components/Card.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Animated,
|
||||||
|
Text,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
const Card = ({ style, children }) => <View style={style}>{children}</View>;
|
||||||
|
|
||||||
|
Card.propTypes = {
|
||||||
|
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
|
||||||
|
style: PropTypes.oneOfType([PropTypes.number, PropTypes.object, PropTypes.array]),
|
||||||
|
onSwipedLeft: PropTypes.func,
|
||||||
|
onSwipedRight:PropTypes.func,
|
||||||
|
onSwipedTop: PropTypes.func,
|
||||||
|
onSwipedBottom: PropTypes.func,
|
||||||
|
onSwiped: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
Card.defaultProps = {
|
||||||
|
style:{},
|
||||||
|
onSwiped: () => {},
|
||||||
|
onSwipedLeft: () => {},
|
||||||
|
onSwipedRight: () => {},
|
||||||
|
onSwipedTop: () => {},
|
||||||
|
onSwipedBottom: () => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Card;
|
528
components/CardStack.tsx
Normal file
528
components/CardStack.tsx
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Animated,
|
||||||
|
PanResponder,
|
||||||
|
Dimensions,
|
||||||
|
Text,
|
||||||
|
Platform
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
const { height, width } = Dimensions.get("window");
|
||||||
|
|
||||||
|
class CardStack extends Component {
|
||||||
|
static distance(x, y) {
|
||||||
|
return Math.hypot(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
drag: new Animated.ValueXY({ x: 0, y: 0 }),
|
||||||
|
dragDistance: new Animated.Value(0),
|
||||||
|
sindex: 0, // index to the next card to be renderd mod card.length
|
||||||
|
cardA: null,
|
||||||
|
cardB: null,
|
||||||
|
topCard: "cardA",
|
||||||
|
cards: [],
|
||||||
|
touchStart: 0,
|
||||||
|
};
|
||||||
|
this.distance = this.constructor.distance;
|
||||||
|
this._panResponder = PanResponder.create({
|
||||||
|
onStartShouldSetPanResponder: (evt, gestureState) => false,
|
||||||
|
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
|
||||||
|
onMoveShouldSetPanResponder: (evt, gestureState) => {
|
||||||
|
const isVerticalSwipe = Math.sqrt(
|
||||||
|
Math.pow(gestureState.dx, 2) < Math.pow(gestureState.dy, 2)
|
||||||
|
)
|
||||||
|
if (!this.props.verticalSwipe && isVerticalSwipe) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Math.sqrt(Math.pow(gestureState.dx, 2) + Math.pow(gestureState.dy, 2)) > 10
|
||||||
|
},
|
||||||
|
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
|
||||||
|
const isVerticalSwipe = Math.sqrt(
|
||||||
|
Math.pow(gestureState.dx, 2) < Math.pow(gestureState.dy, 2)
|
||||||
|
)
|
||||||
|
if (!this.props.verticalSwipe && isVerticalSwipe) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Math.sqrt(Math.pow(gestureState.dx, 2) + Math.pow(gestureState.dy, 2)) > 10
|
||||||
|
},
|
||||||
|
onPanResponderGrant: (evt, gestureState) => {
|
||||||
|
this.props.onSwipeStart();
|
||||||
|
this.setState({ touchStart: new Date().getTime() });
|
||||||
|
},
|
||||||
|
onPanResponderMove: (evt, gestureState) => {
|
||||||
|
const movedX = gestureState.moveX - gestureState.x0;
|
||||||
|
const movedY = gestureState.moveY - gestureState.y0;
|
||||||
|
this.props.onSwipe(movedX, movedY);
|
||||||
|
const { verticalSwipe, horizontalSwipe } = this.props;
|
||||||
|
const dragDistance = this.distance((horizontalSwipe) ? gestureState.dx : 0, (verticalSwipe) ? gestureState.dy : 0);
|
||||||
|
this.state.dragDistance.setValue(dragDistance);
|
||||||
|
this.state.drag.setValue({ x: (horizontalSwipe) ? gestureState.dx : 0, y: (verticalSwipe) ? gestureState.dy : 0 });
|
||||||
|
},
|
||||||
|
onPanResponderTerminationRequest: (evt, gestureState) => true,
|
||||||
|
onPanResponderRelease: (evt, gestureState) => {
|
||||||
|
this.props.onSwipeEnd();
|
||||||
|
const currentTime = new Date().getTime();
|
||||||
|
const swipeDuration = currentTime - this.state.touchStart;
|
||||||
|
const {
|
||||||
|
verticalThreshold,
|
||||||
|
horizontalThreshold,
|
||||||
|
disableTopSwipe,
|
||||||
|
disableLeftSwipe,
|
||||||
|
disableRightSwipe,
|
||||||
|
disableBottomSwipe,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (((Math.abs(gestureState.dx) > horizontalThreshold) ||
|
||||||
|
(Math.abs(gestureState.dx) > horizontalThreshold * 0.6 &&
|
||||||
|
swipeDuration < 150)
|
||||||
|
) && this.props.horizontalSwipe) {
|
||||||
|
|
||||||
|
const swipeDirection = (gestureState.dx < 0) ? width * -1.5 : width * 1.5;
|
||||||
|
if (swipeDirection < 0 && !disableLeftSwipe) {
|
||||||
|
this._nextCard("left", swipeDirection, gestureState.dy, this.props.duration);
|
||||||
|
}
|
||||||
|
else if (swipeDirection > 0 && !disableRightSwipe) {
|
||||||
|
this._nextCard("right", swipeDirection, gestureState.dy, this.props.duration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._resetCard();
|
||||||
|
}
|
||||||
|
} else if (((Math.abs(gestureState.dy) > verticalThreshold) ||
|
||||||
|
(Math.abs(gestureState.dy) > verticalThreshold * 0.8 &&
|
||||||
|
swipeDuration < 150)
|
||||||
|
) && this.props.verticalSwipe) {
|
||||||
|
|
||||||
|
const swipeDirection = (gestureState.dy < 0) ? height * -1 : height;
|
||||||
|
if (swipeDirection < 0 && !disableTopSwipe) {
|
||||||
|
|
||||||
|
this._nextCard("top", gestureState.dx, swipeDirection, this.props.duration);
|
||||||
|
}
|
||||||
|
else if (swipeDirection > 0 && !disableBottomSwipe) {
|
||||||
|
this._nextCard("bottom", gestureState.dx, swipeDirection, this.props.duration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._resetCard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._resetCard();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onPanResponderTerminate: (evt, gestureState) => {
|
||||||
|
},
|
||||||
|
onShouldBlockNativeResponder: (evt, gestureState) => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (typeof this.props.children === "undefined") return;
|
||||||
|
if (!this._isSameChildren(this.props.children, prevProps.children)) {
|
||||||
|
const children = Array.isArray(this.props.children) ? this.props.children : [this.props.children];
|
||||||
|
const aIndex = (this.state.topCard == "cardA") ?
|
||||||
|
this._getIndex(this.state.sindex - 2, children.length) :
|
||||||
|
this._getIndex(this.state.sindex - 1, children.length);
|
||||||
|
const bIndex = (this.state.topCard == "cardB") ?
|
||||||
|
this._getIndex(this.state.sindex - 2, children.length) :
|
||||||
|
this._getIndex(this.state.sindex - 1, children.length);
|
||||||
|
this.setState({
|
||||||
|
cards: children,
|
||||||
|
cardA: children[aIndex] || null,
|
||||||
|
cardB: children[bIndex] || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getIndex(index, cards){
|
||||||
|
return this.props.loop ?
|
||||||
|
this.mod(index, cards):
|
||||||
|
index;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.initDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isSameChildren(a, b) {
|
||||||
|
if (typeof a != typeof b) return false;
|
||||||
|
if (typeof a === "undefined") return false;
|
||||||
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||||||
|
if (a.length != b.length) return false;
|
||||||
|
for (const i in a) {
|
||||||
|
if (a[i].key != b[i].key) { return false }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (a.key !== b.key) return false;
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
initDeck() {
|
||||||
|
if (typeof this.props.children === "undefined") return;
|
||||||
|
const { children, loop } = this.props;
|
||||||
|
const cards = Array.isArray(children) ? children : [children];
|
||||||
|
const initialIndexA = this.props.initialIndex < cards.length ? this.props.initialIndex : 0;
|
||||||
|
const initialIndexB = loop ? this.mod(initialIndexA + 1, cards.length) : initialIndexA + 1;
|
||||||
|
const cardA = cards[initialIndexA] || null;
|
||||||
|
const cardB = cards[initialIndexB] || null;
|
||||||
|
this.setState({
|
||||||
|
cards,
|
||||||
|
cardA,
|
||||||
|
cardB,
|
||||||
|
sindex: initialIndexB + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetCard() {
|
||||||
|
Animated.timing(
|
||||||
|
this.state.dragDistance,
|
||||||
|
{
|
||||||
|
toValue: 0,
|
||||||
|
duration: this.props.duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
Animated.spring(
|
||||||
|
this.state.drag,
|
||||||
|
{
|
||||||
|
toValue: { x: 0, y: 0 },
|
||||||
|
duration: this.props.duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
goBackFromTop() {
|
||||||
|
this._goBack("top");
|
||||||
|
}
|
||||||
|
|
||||||
|
goBackFromRight() {
|
||||||
|
this._goBack("right");
|
||||||
|
}
|
||||||
|
|
||||||
|
goBackFromLeft() {
|
||||||
|
this._goBack("left");
|
||||||
|
}
|
||||||
|
|
||||||
|
goBackFromBottom() {
|
||||||
|
this._goBack("bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
mod(n, m) {
|
||||||
|
return ((n % m) + m) % m;
|
||||||
|
}
|
||||||
|
|
||||||
|
_goBack(direction) {
|
||||||
|
const { cards, sindex, topCard } = this.state;
|
||||||
|
|
||||||
|
if ((sindex - 3) < 0 && !this.props.loop) return;
|
||||||
|
|
||||||
|
const previusCardIndex = this.mod(sindex - 3, cards.length)
|
||||||
|
let update = {};
|
||||||
|
if (topCard === "cardA") {
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
cardB: cards[previusCardIndex]
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
cardA: cards[previusCardIndex],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
...update,
|
||||||
|
topCard: (topCard === "cardA") ? "cardB" : "cardA",
|
||||||
|
sindex: sindex - 1
|
||||||
|
}, () => {
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case "top":
|
||||||
|
this.state.drag.setValue({ x: 0, y: -height });
|
||||||
|
this.state.dragDistance.setValue(height);
|
||||||
|
break;
|
||||||
|
case "left":
|
||||||
|
this.state.drag.setValue({ x: -width, y: 0 });
|
||||||
|
this.state.dragDistance.setValue(width);
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
this.state.drag.setValue({ x: width, y: 0 });
|
||||||
|
this.state.dragDistance.setValue(width);
|
||||||
|
break;
|
||||||
|
case "bottom":
|
||||||
|
this.state.drag.setValue({ x: 0, y: height });
|
||||||
|
this.state.dragDistance.setValue(width);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Animated.spring(
|
||||||
|
this.state.dragDistance,
|
||||||
|
{
|
||||||
|
toValue: 0,
|
||||||
|
duration: this.props.duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
|
||||||
|
Animated.spring(
|
||||||
|
this.state.drag,
|
||||||
|
{
|
||||||
|
toValue: { x: 0, y: 0 },
|
||||||
|
duration: this.props.duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
swipeTop(d = null) {
|
||||||
|
this._nextCard("top", 0, -height, d || this.props.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
swipeBottom(d = null) {
|
||||||
|
this._nextCard("bottom", 0, height, d || this.props.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
swipeRight(d = null) {
|
||||||
|
this._nextCard("right", width * 1.5, 0, d || this.props.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
swipeLeft(d = null) {
|
||||||
|
this._nextCard("left", -width * 1.5, 0, d || this.props.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextCard(direction, x, y, duration = 400) {
|
||||||
|
const { verticalSwipe, horizontalSwipe, loop } = this.props;
|
||||||
|
const { sindex, cards, topCard } = this.state;
|
||||||
|
|
||||||
|
// index for the next card to be renderd
|
||||||
|
const nextCard = (loop) ? (Math.abs(sindex) % cards.length) : sindex;
|
||||||
|
|
||||||
|
// index of the swiped card
|
||||||
|
const index = (loop) ? this.mod(nextCard - 2, cards.length) : nextCard - 2;
|
||||||
|
|
||||||
|
if (index === cards.length - 1) {
|
||||||
|
this.props.onSwipedAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sindex - 2 < cards.length) || (loop)) {
|
||||||
|
Animated.spring(
|
||||||
|
this.state.dragDistance,
|
||||||
|
{
|
||||||
|
toValue: 220,
|
||||||
|
duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
|
||||||
|
Animated.timing(
|
||||||
|
this.state.drag,
|
||||||
|
{
|
||||||
|
toValue: { x: (horizontalSwipe) ? x : 0, y: (verticalSwipe) ? y : 0 },
|
||||||
|
duration,
|
||||||
|
useNativeDriver: this.props.useNativeDriver || false,
|
||||||
|
}
|
||||||
|
).start(() => {
|
||||||
|
|
||||||
|
const newTopCard = (topCard === "cardA") ? "cardB" : "cardA";
|
||||||
|
|
||||||
|
let update = {};
|
||||||
|
if (newTopCard === "cardA") {
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
cardB: cards[nextCard]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (newTopCard === "cardB") {
|
||||||
|
update = {
|
||||||
|
...update,
|
||||||
|
cardA: cards[nextCard],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.state.drag.setValue({ x: 0, y: 0 });
|
||||||
|
this.state.dragDistance.setValue(0);
|
||||||
|
this.setState({
|
||||||
|
...update,
|
||||||
|
topCard: newTopCard,
|
||||||
|
sindex: nextCard + 1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onSwiped(index);
|
||||||
|
switch (direction) {
|
||||||
|
case "left":
|
||||||
|
this.props.onSwipedLeft(index);
|
||||||
|
if (this.state.cards[index] && this.state.cards[index].props.onSwipedLeft)
|
||||||
|
this.state.cards[index] && this.state.cards[index].props.onSwipedLeft();
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
this.props.onSwipedRight(index);
|
||||||
|
if (this.state.cards[index] && this.state.cards[index].props.onSwipedRight)
|
||||||
|
this.state.cards[index].props.onSwipedRight();
|
||||||
|
break;
|
||||||
|
case "top":
|
||||||
|
this.props.onSwipedTop(index);
|
||||||
|
if (this.state.cards[index] && this.state.cards[index].props.onSwipedTop)
|
||||||
|
this.state.cards[index].props.onSwipedTop();
|
||||||
|
break;
|
||||||
|
case "bottom":
|
||||||
|
this.props.onSwipedBottom(index);
|
||||||
|
if (this.state.cards[index] && this.state.cards[index].props.onSwipedBottom)
|
||||||
|
this.state.cards[index].props.onSwipedBottom();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description CardB’s click feature is trigger the CardA on the card stack. (Solved on Android)
|
||||||
|
* @see https://facebook.github.io/react-native/docs/view#pointerevents
|
||||||
|
*/
|
||||||
|
_setPointerEvents(topCard, topCardName) {
|
||||||
|
return { pointerEvents: topCard === topCardName ? "auto" : "none" }
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const { secondCardZoom, renderNoMoreCards } = this.props;
|
||||||
|
const { drag, dragDistance, cardA, cardB, topCard, sindex } = this.state;
|
||||||
|
|
||||||
|
const scale = dragDistance.interpolate({
|
||||||
|
inputRange: [0, 10, 220],
|
||||||
|
outputRange: [secondCardZoom, secondCardZoom, 1],
|
||||||
|
extrapolate: "clamp",
|
||||||
|
});
|
||||||
|
const rotate = drag.x.interpolate({
|
||||||
|
inputRange: [width * -1.5, 0, width * 1.5],
|
||||||
|
outputRange: this.props.outputRotationRange,
|
||||||
|
extrapolate: "clamp",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View {...this._panResponder.panHandlers} style={[{ position: "relative" }, this.props.style]}>
|
||||||
|
|
||||||
|
{renderNoMoreCards()}
|
||||||
|
|
||||||
|
<Animated.View
|
||||||
|
{...this._setPointerEvents(topCard, "cardB")}
|
||||||
|
style={[{
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: (topCard === "cardB") ? 3 : 2,
|
||||||
|
...Platform.select({
|
||||||
|
android: {
|
||||||
|
elevation: (topCard === "cardB") ? 3 : 2,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
transform: [
|
||||||
|
{ rotate: (topCard === "cardB") ? rotate : "0deg" },
|
||||||
|
{ translateX: (topCard === "cardB") ? drag.x : 0 },
|
||||||
|
{ translateY: (topCard === "cardB") ? drag.y : 0 },
|
||||||
|
{ scale: (topCard === "cardB") ? 1 : scale },
|
||||||
|
]
|
||||||
|
}, this.props.cardContainerStyle]}>
|
||||||
|
{cardB}
|
||||||
|
</Animated.View>
|
||||||
|
<Animated.View
|
||||||
|
{...this._setPointerEvents(topCard, "cardA")}
|
||||||
|
style={[{
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: (topCard === "cardA") ? 3 : 2,
|
||||||
|
...Platform.select({
|
||||||
|
android: {
|
||||||
|
elevation: (topCard === "cardA") ? 3 : 2,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
transform: [
|
||||||
|
{ rotate: (topCard === "cardA") ? rotate : "0deg" },
|
||||||
|
{ translateX: (topCard === "cardA") ? drag.x : 0 },
|
||||||
|
{ translateY: (topCard === "cardA") ? drag.y : 0 },
|
||||||
|
{ scale: (topCard === "cardA") ? 1 : scale },
|
||||||
|
]
|
||||||
|
}, this.props.cardContainerStyle]}>
|
||||||
|
{cardA}
|
||||||
|
</Animated.View>
|
||||||
|
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CardStack.propTypes = {
|
||||||
|
|
||||||
|
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
|
||||||
|
|
||||||
|
style: PropTypes.oneOfType([PropTypes.number, PropTypes.object, PropTypes.array]),
|
||||||
|
cardContainerStyle: PropTypes.oneOfType([PropTypes.number, PropTypes.object, PropTypes.array]),
|
||||||
|
secondCardZoom: PropTypes.number,
|
||||||
|
loop: PropTypes.bool,
|
||||||
|
initialIndex: PropTypes.number,
|
||||||
|
renderNoMoreCards: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
||||||
|
onSwipeStart: PropTypes.func,
|
||||||
|
onSwipeEnd: PropTypes.func,
|
||||||
|
onSwiped: PropTypes.func,
|
||||||
|
onSwipedLeft: PropTypes.func,
|
||||||
|
onSwipedRight: PropTypes.func,
|
||||||
|
onSwipedTop: PropTypes.func,
|
||||||
|
onSwipedBottom: PropTypes.func,
|
||||||
|
onSwiped: PropTypes.func,
|
||||||
|
onSwipedAll: PropTypes.func,
|
||||||
|
onSwipe: PropTypes.func,
|
||||||
|
|
||||||
|
disableBottomSwipe: PropTypes.bool,
|
||||||
|
disableLeftSwipe: PropTypes.bool,
|
||||||
|
disableRightSwipe: PropTypes.bool,
|
||||||
|
disableTopSwipe: PropTypes.bool,
|
||||||
|
verticalSwipe: PropTypes.bool,
|
||||||
|
verticalThreshold: PropTypes.number,
|
||||||
|
|
||||||
|
horizontalSwipe: PropTypes.bool,
|
||||||
|
horizontalThreshold: PropTypes.number,
|
||||||
|
outputRotationRange: PropTypes.array,
|
||||||
|
duration: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
|
CardStack.defaultProps = {
|
||||||
|
|
||||||
|
style: {},
|
||||||
|
cardContainerStyle: {},
|
||||||
|
secondCardZoom: 0.95,
|
||||||
|
loop: false,
|
||||||
|
initialIndex: 0,
|
||||||
|
renderNoMoreCards: () => { return (<Text>No More Cards</Text>) },
|
||||||
|
onSwipeStart: () => null,
|
||||||
|
onSwipeEnd: () => null,
|
||||||
|
onSwiped: () => { },
|
||||||
|
onSwipedLeft: () => { },
|
||||||
|
onSwipedRight: () => { },
|
||||||
|
onSwipedTop: () => { },
|
||||||
|
onSwipedBottom: () => { },
|
||||||
|
onSwipedAll: async () => { },
|
||||||
|
onSwipe: () => { },
|
||||||
|
|
||||||
|
disableBottomSwipe: false,
|
||||||
|
disableLeftSwipe: false,
|
||||||
|
disableRightSwipe: false,
|
||||||
|
disableTopSwipe: false,
|
||||||
|
verticalSwipe: true,
|
||||||
|
verticalThreshold: height / 4,
|
||||||
|
horizontalSwipe: true,
|
||||||
|
horizontalThreshold: width / 2,
|
||||||
|
outputRotationRange: ["-15deg", "0deg", "15deg"],
|
||||||
|
duration: 300
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardStack;
|
27
components/SuggestionCard.tsx
Normal file
27
components/SuggestionCard.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import React from "react";
|
||||||
|
import styles from "../assets/styles";
|
||||||
|
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
const SuggestionCard = ({
|
||||||
|
actions,
|
||||||
|
description,
|
||||||
|
image,
|
||||||
|
matches,
|
||||||
|
name,
|
||||||
|
onPressLeft,
|
||||||
|
onPressRight,
|
||||||
|
status,
|
||||||
|
variant,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<View style={styles.suggestionsCard}>
|
||||||
|
<Text>NAME IS {name}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SuggestionCard;
|
11
index.js
Normal file
11
index.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import React from "react";
|
||||||
|
import { AppRegistry } from "react-native";
|
||||||
|
import App from "./App";
|
||||||
|
import { name as appName } from "./app.json";
|
||||||
|
import { NavigationContainer } from "@react-navigation/native";
|
||||||
|
|
||||||
|
export default function Main() {
|
||||||
|
return <NavigationContainer><App /></NavigationContainer>;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppRegistry.registerComponent(appName, () => Main);
|
1
metro.config.js
Normal file
1
metro.config.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = {};
|
18703
package-lock.json
generated
Normal file
18703
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
23
package.json
Normal file
23
package.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"start": "npx @react-native-community/cli start",
|
||||||
|
"android": "npx @react-native-community/cli run-android",
|
||||||
|
"lint": "eslint . --ext .js,.tsx --fix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/metro-config": "^0.1.82",
|
||||||
|
"@react-native-community/cli": "^5.0.1",
|
||||||
|
"@react-navigation/native": "^6.0.2",
|
||||||
|
"react-native": "^0.64.0",
|
||||||
|
"react-native-cli": "^2.0.1",
|
||||||
|
"react-native-safe-area-context": "^3.3.0",
|
||||||
|
"react-native-screens": "^3.5.0",
|
||||||
|
"react-navigation": "^4.4.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||||
|
"@typescript-eslint/parser": "^4.29.1",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"typescript": "^4.3.5"
|
||||||
|
}
|
||||||
|
}
|
36
pages/Home.tsx
Normal file
36
pages/Home.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Animated,
|
||||||
|
Text,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
import styles from "../assets/styles";
|
||||||
|
import demoData from "../assets/data/demo";
|
||||||
|
|
||||||
|
import Card from "../components/Card";
|
||||||
|
import CardStack from "../components/CardStack";
|
||||||
|
import SuggestionCard from "../components/SuggestionCard";
|
||||||
|
|
||||||
|
class Home extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<CardStack
|
||||||
|
ref={swiper => (this.swiper = swiper)}
|
||||||
|
verticalSwipe={false}
|
||||||
|
>
|
||||||
|
{demoData.map((item, index) => (
|
||||||
|
<Card key={index}>
|
||||||
|
<SuggestionCard
|
||||||
|
name={item.name}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</CardStack>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home;
|
Loading…
Reference in a new issue