diff --git a/.travis.yml b/.travis.yml
index 62a9ccd..cc92950 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,8 +16,10 @@ android:
- tools
- build-tools-27.0.3
- build-tools-26.0.3
+ - build-tools-23.0.2
- android-27
- android-26
+ - android-23
- extra-android-m2repository
- extra-google-google_play_services
- extra-google-m2repository
diff --git a/outloud/android/app/build.gradle b/outloud/android/app/build.gradle
index 19fb3cc..7640ea1 100644
--- a/outloud/android/app/build.gradle
+++ b/outloud/android/app/build.gradle
@@ -149,9 +149,13 @@ android {
}
dependencies {
- api project(':react-native-sentry')
- api project(':react-native-vector-icons')
- api project(':react-native-auth0')
+ implementation project(':react-native-material-snackbar')
+ implementation project(':react-native-audio')
+ implementation project(':react-native-voice')
+ implementation project(':react-native-sound')
+ implementation project(':react-native-sentry')
+ implementation project(':react-native-vector-icons')
+ implementation project(':react-native-auth0')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation "com.facebook.react:react-native:+" // From node_modules
diff --git a/outloud/android/app/src/main/AndroidManifest.xml b/outloud/android/app/src/main/AndroidManifest.xml
index c7a6607..f65e86a 100644
--- a/outloud/android/app/src/main/AndroidManifest.xml
+++ b/outloud/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
+
getPackages() {
return Arrays.asList(
new MainReactPackage(),
+ new ReactNativeAudioPackage(),
+ new VoicePackage(),
+ new RNSoundPackage(),
new RNSentryPackage(),
new VectorIconsPackage(),
- new A0Auth0Package()
+ new A0Auth0Package(),
+ new SnackbarPackage()
);
}
diff --git a/outloud/android/build.gradle b/outloud/android/build.gradle
index 85d8f2f..33bc962 100644
--- a/outloud/android/build.gradle
+++ b/outloud/android/build.gradle
@@ -5,7 +5,7 @@ buildscript {
buildToolsVersion = "27.0.3"
minSdkVersion = 16
compileSdkVersion = 27
- targetSdkVersion = 26
+ targetSdkVersion = 23
supportLibVersion = "27.1.1"
}
repositories {
@@ -32,6 +32,16 @@ allprojects {
}
}
+subprojects {
+ afterEvaluate {project ->
+ if (project.hasProperty("android")) {
+ android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+ }
+ }
+ }
+}
task wrapper(type: Wrapper) {
gradleVersion = '4.4'
diff --git a/outloud/android/settings.gradle b/outloud/android/settings.gradle
index 87e43e3..d7950f1 100644
--- a/outloud/android/settings.gradle
+++ b/outloud/android/settings.gradle
@@ -1,4 +1,12 @@
rootProject.name = 'outloud'
+include ':react-native-material-snackbar'
+project(':react-native-material-snackbar').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-material-snackbar/android')
+include ':react-native-audio'
+project(':react-native-audio').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-audio/android')
+include ':react-native-voice'
+project(':react-native-voice').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-voice/android')
+include ':react-native-sound'
+project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
include ':react-native-sentry'
project(':react-native-sentry').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sentry/android')
include ':react-native-vector-icons'
diff --git a/outloud/assets/fonts/Roboto-Black.ttf b/outloud/assets/fonts/Roboto-Black.ttf
new file mode 100644
index 0000000..689fe5c
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Black.ttf differ
diff --git a/outloud/assets/fonts/Roboto-BlackItalic.ttf b/outloud/assets/fonts/Roboto-BlackItalic.ttf
new file mode 100644
index 0000000..0b4e0ee
Binary files /dev/null and b/outloud/assets/fonts/Roboto-BlackItalic.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Bold.ttf b/outloud/assets/fonts/Roboto-Bold.ttf
new file mode 100644
index 0000000..d3f01ad
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Bold.ttf differ
diff --git a/outloud/assets/fonts/Roboto-BoldItalic.ttf b/outloud/assets/fonts/Roboto-BoldItalic.ttf
new file mode 100644
index 0000000..41cc1e7
Binary files /dev/null and b/outloud/assets/fonts/Roboto-BoldItalic.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Italic.ttf b/outloud/assets/fonts/Roboto-Italic.ttf
new file mode 100644
index 0000000..6a1cee5
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Italic.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Light.ttf b/outloud/assets/fonts/Roboto-Light.ttf
new file mode 100644
index 0000000..219063a
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Light.ttf differ
diff --git a/outloud/assets/fonts/Roboto-LightItalic.ttf b/outloud/assets/fonts/Roboto-LightItalic.ttf
new file mode 100644
index 0000000..0e81e87
Binary files /dev/null and b/outloud/assets/fonts/Roboto-LightItalic.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Medium.ttf b/outloud/assets/fonts/Roboto-Medium.ttf
new file mode 100644
index 0000000..1a7f3b0
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Medium.ttf differ
diff --git a/outloud/assets/fonts/Roboto-MediumItalic.ttf b/outloud/assets/fonts/Roboto-MediumItalic.ttf
new file mode 100644
index 0000000..0030295
Binary files /dev/null and b/outloud/assets/fonts/Roboto-MediumItalic.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Regular.ttf b/outloud/assets/fonts/Roboto-Regular.ttf
new file mode 100644
index 0000000..2c97eea
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Regular.ttf differ
diff --git a/outloud/assets/fonts/Roboto-Thin.ttf b/outloud/assets/fonts/Roboto-Thin.ttf
new file mode 100644
index 0000000..b74a4fd
Binary files /dev/null and b/outloud/assets/fonts/Roboto-Thin.ttf differ
diff --git a/outloud/assets/fonts/Roboto-ThinItalic.ttf b/outloud/assets/fonts/Roboto-ThinItalic.ttf
new file mode 100644
index 0000000..dd0ddb8
Binary files /dev/null and b/outloud/assets/fonts/Roboto-ThinItalic.ttf differ
diff --git a/outloud/ios/outloud.xcodeproj/project.pbxproj b/outloud/ios/outloud.xcodeproj/project.pbxproj
index 4f5ad58..f04cf8f 100644
--- a/outloud/ios/outloud.xcodeproj/project.pbxproj
+++ b/outloud/ios/outloud.xcodeproj/project.pbxproj
@@ -55,6 +55,22 @@
1B1C5942D03E426CB9C2FB7F /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 99D1C6418F98414CA5DC2CC2 /* Zocial.ttf */; };
6E87516B04464D49950A7DBC /* libRNSentry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0011225C01B04BED8717C24B /* libRNSentry.a */; };
17CC0BFB5A624B2B897B62A6 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 600D0A678C1245F89E9AA624 /* libz.tbd */; };
+ C368EDA246F4490382B2886E /* libRNSound.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40243AE54810444B832F8D38 /* libRNSound.a */; };
+ 72ACB5CDBF8B447A8EE4F89F /* libVoice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EA99F25621E04EFFAC020AB0 /* libVoice.a */; };
+ E201F574E01142AFBE907C66 /* libRNAudio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF434C4CB34C407F9A863728 /* libRNAudio.a */; };
+ E73F686B592A41A1B015AD45 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 135B0E9FBC65497BB45FD06C /* Roboto-Black.ttf */; };
+ 782EBCC990B14664ADE289E3 /* Roboto-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C4387D9D344741E291D64D42 /* Roboto-BlackItalic.ttf */; };
+ 866E201B1F0B474BA7A6C2C0 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B0DC5D417F52448C9CC62184 /* Roboto-Bold.ttf */; };
+ 8F9F6CA1333B4D7CA585D88A /* Roboto-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EF96CC68FC9B4DFB9F9A23F7 /* Roboto-BoldItalic.ttf */; };
+ 1BBFF6F0B4E1431C91B1162B /* Roboto-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3D8A312318074AF98021EB47 /* Roboto-Italic.ttf */; };
+ 9497E929F49047D895925BDE /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EB8553DE174E44958C2A4AE9 /* Roboto-Light.ttf */; };
+ 51F09EAC113C4E8BBB8E095F /* Roboto-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1787CBF96DFB42E0969D4CE3 /* Roboto-LightItalic.ttf */; };
+ 5C75C6D02E574BC18239F89A /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = CC7867C91AEB4A6DBE49FF06 /* Roboto-Medium.ttf */; };
+ 15771437A12844BE89D58EC1 /* Roboto-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0F83C07630BD47769F1FF957 /* Roboto-MediumItalic.ttf */; };
+ 7879C6D27C994C75818E5A18 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = ACCC5362EEA94A879E60142D /* Roboto-Regular.ttf */; };
+ 14C4C74581BF49478DB7CB2A /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 38CA45D6CFA346A2B346E51D /* Roboto-Thin.ttf */; };
+ 8C6A361475084EA9B180A8DF /* Roboto-ThinItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FA26CAA426534751A03BE0DA /* Roboto-ThinItalic.ttf */; };
+ D1D9496D750C4EECAF434723 /* libRNSnackbar.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A742A82490AF476099C0D88F /* libRNSnackbar.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -381,6 +397,26 @@
6912CC50CEEB4960B1D13FD8 /* RNSentry.xcodeproj */ = {isa = PBXFileReference; name = "RNSentry.xcodeproj"; path = "../node_modules/react-native-sentry/ios/RNSentry.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
0011225C01B04BED8717C24B /* libRNSentry.a */ = {isa = PBXFileReference; name = "libRNSentry.a"; path = "libRNSentry.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
600D0A678C1245F89E9AA624 /* libz.tbd */ = {isa = PBXFileReference; name = "libz.tbd"; path = "usr/lib/libz.tbd"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = sourcecode.text-based-dylib-definition; explicitFileType = undefined; includeInIndex = 0; };
+ 1F2DE364E8B540A9BCCE2C1E /* RNSound.xcodeproj */ = {isa = PBXFileReference; name = "RNSound.xcodeproj"; path = "../node_modules/react-native-sound/RNSound.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+ 40243AE54810444B832F8D38 /* libRNSound.a */ = {isa = PBXFileReference; name = "libRNSound.a"; path = "libRNSound.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+ 4FF8CAA1F571411CB1D2DDC4 /* Voice.xcodeproj */ = {isa = PBXFileReference; name = "Voice.xcodeproj"; path = "../node_modules/react-native-voice/ios/Voice.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+ EA99F25621E04EFFAC020AB0 /* libVoice.a */ = {isa = PBXFileReference; name = "libVoice.a"; path = "libVoice.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+ AA2BCE2484104CC185506AE8 /* RNAudio.xcodeproj */ = {isa = PBXFileReference; name = "RNAudio.xcodeproj"; path = "../node_modules/react-native-audio/ios/RNAudio.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+ BF434C4CB34C407F9A863728 /* libRNAudio.a */ = {isa = PBXFileReference; name = "libRNAudio.a"; path = "libRNAudio.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+ 135B0E9FBC65497BB45FD06C /* Roboto-Black.ttf */ = {isa = PBXFileReference; name = "Roboto-Black.ttf"; path = "../assets/fonts/Roboto-Black.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ C4387D9D344741E291D64D42 /* Roboto-BlackItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-BlackItalic.ttf"; path = "../assets/fonts/Roboto-BlackItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ B0DC5D417F52448C9CC62184 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; name = "Roboto-Bold.ttf"; path = "../assets/fonts/Roboto-Bold.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ EF96CC68FC9B4DFB9F9A23F7 /* Roboto-BoldItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-BoldItalic.ttf"; path = "../assets/fonts/Roboto-BoldItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ 3D8A312318074AF98021EB47 /* Roboto-Italic.ttf */ = {isa = PBXFileReference; name = "Roboto-Italic.ttf"; path = "../assets/fonts/Roboto-Italic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ EB8553DE174E44958C2A4AE9 /* Roboto-Light.ttf */ = {isa = PBXFileReference; name = "Roboto-Light.ttf"; path = "../assets/fonts/Roboto-Light.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ 1787CBF96DFB42E0969D4CE3 /* Roboto-LightItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-LightItalic.ttf"; path = "../assets/fonts/Roboto-LightItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ CC7867C91AEB4A6DBE49FF06 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; name = "Roboto-Medium.ttf"; path = "../assets/fonts/Roboto-Medium.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ 0F83C07630BD47769F1FF957 /* Roboto-MediumItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-MediumItalic.ttf"; path = "../assets/fonts/Roboto-MediumItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ ACCC5362EEA94A879E60142D /* Roboto-Regular.ttf */ = {isa = PBXFileReference; name = "Roboto-Regular.ttf"; path = "../assets/fonts/Roboto-Regular.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ 38CA45D6CFA346A2B346E51D /* Roboto-Thin.ttf */ = {isa = PBXFileReference; name = "Roboto-Thin.ttf"; path = "../assets/fonts/Roboto-Thin.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ FA26CAA426534751A03BE0DA /* Roboto-ThinItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-ThinItalic.ttf"; path = "../assets/fonts/Roboto-ThinItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+ D6EB5E7F37D74D98B136B8D6 /* RNSnackbar.xcodeproj */ = {isa = PBXFileReference; name = "RNSnackbar.xcodeproj"; path = "../node_modules/react-native-material-snackbar/ios/RNSnackbar.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+ A742A82490AF476099C0D88F /* libRNSnackbar.a */ = {isa = PBXFileReference; name = "libRNSnackbar.a"; path = "libRNSnackbar.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -412,6 +448,10 @@
5D0C14CD548548A389E27040 /* libRNVectorIcons.a in Frameworks */,
6E87516B04464D49950A7DBC /* libRNSentry.a in Frameworks */,
17CC0BFB5A624B2B897B62A6 /* libz.tbd in Frameworks */,
+ C368EDA246F4490382B2886E /* libRNSound.a in Frameworks */,
+ 72ACB5CDBF8B447A8EE4F89F /* libVoice.a in Frameworks */,
+ E201F574E01142AFBE907C66 /* libRNAudio.a in Frameworks */,
+ D1D9496D750C4EECAF434723 /* libRNSnackbar.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -602,6 +642,10 @@
7A84098CE45E4444BE0F1050 /* A0Auth0.xcodeproj */,
C005F086220645DBB7ECBCAA /* RNVectorIcons.xcodeproj */,
6912CC50CEEB4960B1D13FD8 /* RNSentry.xcodeproj */,
+ 1F2DE364E8B540A9BCCE2C1E /* RNSound.xcodeproj */,
+ 4FF8CAA1F571411CB1D2DDC4 /* Voice.xcodeproj */,
+ AA2BCE2484104CC185506AE8 /* RNAudio.xcodeproj */,
+ D6EB5E7F37D74D98B136B8D6 /* RNSnackbar.xcodeproj */,
);
name = Libraries;
sourceTree = "";
@@ -667,6 +711,18 @@
E8E0D58B1498483D8E6582C3 /* Octicons.ttf */,
12A24819709C47D79BA4F33A /* SimpleLineIcons.ttf */,
99D1C6418F98414CA5DC2CC2 /* Zocial.ttf */,
+ 135B0E9FBC65497BB45FD06C /* Roboto-Black.ttf */,
+ C4387D9D344741E291D64D42 /* Roboto-BlackItalic.ttf */,
+ B0DC5D417F52448C9CC62184 /* Roboto-Bold.ttf */,
+ EF96CC68FC9B4DFB9F9A23F7 /* Roboto-BoldItalic.ttf */,
+ 3D8A312318074AF98021EB47 /* Roboto-Italic.ttf */,
+ EB8553DE174E44958C2A4AE9 /* Roboto-Light.ttf */,
+ 1787CBF96DFB42E0969D4CE3 /* Roboto-LightItalic.ttf */,
+ CC7867C91AEB4A6DBE49FF06 /* Roboto-Medium.ttf */,
+ 0F83C07630BD47769F1FF957 /* Roboto-MediumItalic.ttf */,
+ ACCC5362EEA94A879E60142D /* Roboto-Regular.ttf */,
+ 38CA45D6CFA346A2B346E51D /* Roboto-Thin.ttf */,
+ FA26CAA426534751A03BE0DA /* Roboto-ThinItalic.ttf */,
);
name = Resources;
sourceTree = "";
@@ -1132,6 +1188,18 @@
69145DD3D57B441AB84EAB0C /* Octicons.ttf in Resources */,
E0442497C58E4847B4BC7906 /* SimpleLineIcons.ttf in Resources */,
1B1C5942D03E426CB9C2FB7F /* Zocial.ttf in Resources */,
+ E73F686B592A41A1B015AD45 /* Roboto-Black.ttf in Resources */,
+ 782EBCC990B14664ADE289E3 /* Roboto-BlackItalic.ttf in Resources */,
+ 866E201B1F0B474BA7A6C2C0 /* Roboto-Bold.ttf in Resources */,
+ 8F9F6CA1333B4D7CA585D88A /* Roboto-BoldItalic.ttf in Resources */,
+ 1BBFF6F0B4E1431C91B1162B /* Roboto-Italic.ttf in Resources */,
+ 9497E929F49047D895925BDE /* Roboto-Light.ttf in Resources */,
+ 51F09EAC113C4E8BBB8E095F /* Roboto-LightItalic.ttf in Resources */,
+ 5C75C6D02E574BC18239F89A /* Roboto-Medium.ttf in Resources */,
+ 15771437A12844BE89D58EC1 /* Roboto-MediumItalic.ttf in Resources */,
+ 7879C6D27C994C75818E5A18 /* Roboto-Regular.ttf in Resources */,
+ 14C4C74581BF49478DB7CB2A /* Roboto-Thin.ttf in Resources */,
+ 8C6A361475084EA9B180A8DF /* Roboto-ThinItalic.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1275,6 +1343,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Debug;
@@ -1305,6 +1377,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Release;
@@ -1330,6 +1406,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Debug;
@@ -1354,6 +1434,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Release;
@@ -1392,6 +1476,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Debug;
@@ -1430,6 +1518,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Release;
@@ -1467,6 +1559,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Debug;
@@ -1504,6 +1600,10 @@
"$(SRCROOT)\..\node_modules\react-native-auth0\ios",
"$(SRCROOT)\..\node_modules\react-native-vector-icons\RNVectorIconsManager",
"$(SRCROOT)\..\node_modules\react-native-sentry\ios/**",
+ "$(SRCROOT)\..\node_modules\react-native-sound\RNSound",
+ "$(SRCROOT)\..\node_modules\react-native-voice\ios\Voice",
+ "$(SRCROOT)\..\node_modules\react-native-audio\ios",
+ "$(SRCROOT)\..\node_modules\react-native-material-snackbar\ios",
);
};
name = Release;
diff --git a/outloud/ios/outloud/Info.plist b/outloud/ios/outloud/Info.plist
index 062acec..f64d1ca 100644
--- a/outloud/ios/outloud/Info.plist
+++ b/outloud/ios/outloud/Info.plist
@@ -69,6 +69,18 @@
Octicons.ttf
SimpleLineIcons.ttf
Zocial.ttf
+ Roboto-Black.ttf
+ Roboto-BlackItalic.ttf
+ Roboto-Bold.ttf
+ Roboto-BoldItalic.ttf
+ Roboto-Italic.ttf
+ Roboto-Light.ttf
+ Roboto-LightItalic.ttf
+ Roboto-Medium.ttf
+ Roboto-MediumItalic.ttf
+ Roboto-Regular.ttf
+ Roboto-Thin.ttf
+ Roboto-ThinItalic.ttf
diff --git a/outloud/package-lock.json b/outloud/package-lock.json
index 96a01a4..2888eb7 100644
--- a/outloud/package-lock.json
+++ b/outloud/package-lock.json
@@ -2545,6 +2545,15 @@
"object-visit": "^1.0.0"
}
},
+ "color": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
+ "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
+ "requires": {
+ "color-convert": "^1.9.1",
+ "color-string": "^1.5.2"
+ }
+ },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -2558,6 +2567,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
+ "color-string": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
+ "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
+ "requires": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
@@ -3420,13 +3438,11 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3443,8 +3459,7 @@
},
"concat-map": {
"version": "0.0.1",
- "bundled": true,
- "optional": true
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
@@ -3573,7 +3588,6 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -6016,6 +6030,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
+ "lodash.merge": {
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
+ "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ=="
+ },
"lodash.pad": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz",
@@ -7277,6 +7296,19 @@
"yargs": "^9.0.0"
}
},
+ "react-native-action-button": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/react-native-action-button/-/react-native-action-button-2.8.5.tgz",
+ "integrity": "sha512-BvGZpzuGeuFR2Y6j93+vKiSqDhsF87VHvNXFs/qEYKfzT4b1ASAT/GQbgS6gNt4jRJCUnJWYrIwlBzRjesZQmQ==",
+ "requires": {
+ "prop-types": "^15.5.10"
+ }
+ },
+ "react-native-audio": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/react-native-audio/-/react-native-audio-4.2.1.tgz",
+ "integrity": "sha512-vRKuvAgJZOi6wsIhI6L22vyrulBHt74WtQofj//0mgjbWl3Pcz685lYWHBCVV5jHxu334q+tqZiQbix7jXwrhA=="
+ },
"react-native-auth0": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-native-auth0/-/react-native-auth0-1.3.0.tgz",
@@ -7307,6 +7339,95 @@
"react-native-drawer-layout": "1.3.2"
}
},
+ "react-native-material-bottom-navigation": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/react-native-material-bottom-navigation/-/react-native-material-bottom-navigation-1.0.2.tgz",
+ "integrity": "sha512-xPI9EUqBlYC1U970tZ0eX0VP7mmiZYYemnn2JWmj2xDqzdrdjEZF50woLZdRb2SnzCwC7tUb1MfSaV1T52GP8w==",
+ "requires": {
+ "prop-types": "^15.6.1"
+ }
+ },
+ "react-native-material-buttons": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/react-native-material-buttons/-/react-native-material-buttons-0.5.0.tgz",
+ "integrity": "sha1-qys+P8P1AMpxP1Hp11l4r/YCFSo=",
+ "requires": {
+ "prop-types": "^15.5.9",
+ "react-native-material-ripple": "^0.7.0"
+ },
+ "dependencies": {
+ "react-native-material-ripple": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/react-native-material-ripple/-/react-native-material-ripple-0.7.5.tgz",
+ "integrity": "sha1-4q9REGgFMvFK6jw6Q4JHvi/+9lk=",
+ "requires": {
+ "prop-types": "^15.5.10"
+ }
+ }
+ }
+ },
+ "react-native-material-design-styles": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/react-native-material-design-styles/-/react-native-material-design-styles-0.2.7.tgz",
+ "integrity": "sha512-dEtVROG1zqso3fiElJulOU+8/HwWh2TVIyDICrddlyAuDt5dpowelLpmamkRW1CV8VHRdHY5ZhxGWUOiPvROgw=="
+ },
+ "react-native-material-dropdown": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/react-native-material-dropdown/-/react-native-material-dropdown-0.11.1.tgz",
+ "integrity": "sha1-wP5DSo5heUHvkQukTS8HyPN1hP4=",
+ "requires": {
+ "prop-types": "^15.5.9",
+ "react-native-material-buttons": "^0.5.0",
+ "react-native-material-ripple": "^0.8.0",
+ "react-native-material-textfield": "^0.12.0"
+ }
+ },
+ "react-native-material-ripple": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/react-native-material-ripple/-/react-native-material-ripple-0.8.0.tgz",
+ "integrity": "sha1-uMJOb96iryoh6EaLH0CzVIMBni8=",
+ "requires": {
+ "prop-types": "^15.5.10"
+ }
+ },
+ "react-native-material-snackbar": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/react-native-material-snackbar/-/react-native-material-snackbar-0.0.1.tgz",
+ "integrity": "sha512-hwyx4RShP3ueYKHKbrSBdwaJnwLVA8zFXRfh/dUPrQxb4roKMIDxKCockN1wEPV6V74KfuEi0tLuH85bhKfHYg=="
+ },
+ "react-native-material-textfield": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/react-native-material-textfield/-/react-native-material-textfield-0.12.0.tgz",
+ "integrity": "sha1-P7oZ12q4n2cFLIHgghUvwkPYKj8=",
+ "requires": {
+ "prop-types": "^15.5.9"
+ }
+ },
+ "react-native-material-ui": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/react-native-material-ui/-/react-native-material-ui-1.30.1.tgz",
+ "integrity": "sha512-lvcfDMdPRUloVHVNbQR62h2pCoGOlwWEcC5UEzUNlPX7lRZt/A13PLHIj8wSkE4giwg4GZI9LWY0yqCKxsAq/Q==",
+ "requires": {
+ "color": "3.0.0",
+ "hoist-non-react-statics": "^2.5.5",
+ "lodash.merge": "^4.0.0",
+ "prop-types": "^15.5.10",
+ "react-native-material-design-styles": "^0.2.6"
+ }
+ },
+ "react-native-md-textinput": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/react-native-md-textinput/-/react-native-md-textinput-2.0.4.tgz",
+ "integrity": "sha1-n4HP8WzroLxZX8WO0SOb0TpAI6g="
+ },
+ "react-native-progress": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/react-native-progress/-/react-native-progress-3.5.0.tgz",
+ "integrity": "sha512-Tgc002D0BGes1fTlObu/qNItlsTPYKFrF9XRQaJLme77TNxNX9I04sgIz3kaq8O4R+z/jlai64dk1HDEDQhzMA==",
+ "requires": {
+ "prop-types": "^15.5.8"
+ }
+ },
"react-native-safe-area-view": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.11.0.tgz",
@@ -7329,6 +7450,11 @@
"raven-js": "^3.24.2"
}
},
+ "react-native-sound": {
+ "version": "0.10.9",
+ "resolved": "https://registry.npmjs.org/react-native-sound/-/react-native-sound-0.10.9.tgz",
+ "integrity": "sha1-awCw9K/QF83gn7udFx3xtdW4Uag="
+ },
"react-native-tab-view": {
"version": "0.0.77",
"resolved": "http://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz",
@@ -7369,6 +7495,11 @@
}
}
},
+ "react-native-voice": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/react-native-voice/-/react-native-voice-0.2.6.tgz",
+ "integrity": "sha512-WeNlNNtYDxwyym203yzjTDDCH9iLThi24W85p0oP/0DS9jZ6B6WsPYidWyKg6Qv1TrOq/gHz9vwQLZforM7u3w=="
+ },
"react-navigation": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-2.17.0.tgz",
@@ -8261,6 +8392,21 @@
}
}
},
+ "simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+ "requires": {
+ "is-arrayish": "^0.3.1"
+ },
+ "dependencies": {
+ "is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ }
+ }
+ },
"sisteransi": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz",
diff --git a/outloud/package.json b/outloud/package.json
index cfc4297..688a5c8 100644
--- a/outloud/package.json
+++ b/outloud/package.json
@@ -10,9 +10,20 @@
"jwt-decode": "^2.2.0",
"react": "16.5.0",
"react-native": "0.57.1",
+ "react-native-action-button": "^2.8.5",
+ "react-native-audio": "^4.2.1",
"react-native-auth0": "^1.3.0",
+ "react-native-material-bottom-navigation": "^1.0.2",
+ "react-native-material-dropdown": "^0.11.1",
+ "react-native-material-snackbar": "0.0.1",
+ "react-native-material-textfield": "^0.12.0",
+ "react-native-material-ui": "^1.30.1",
+ "react-native-md-textinput": "^2.0.4",
+ "react-native-progress": "^3.5.0",
"react-native-sentry": "^0.39.0",
+ "react-native-sound": "^0.10.9",
"react-native-vector-icons": "^5.0.0",
+ "react-native-voice": "^0.2.6",
"react-navigation": "^2.17.0"
},
"devDependencies": {
@@ -24,5 +35,10 @@
},
"jest": {
"preset": "react-native"
+ },
+ "rnpm": {
+ "assets": [
+ "./assets/fonts"
+ ]
}
}
diff --git a/outloud/resources/button.png b/outloud/resources/button.png
new file mode 100644
index 0000000..628272e
Binary files /dev/null and b/outloud/resources/button.png differ
diff --git a/outloud/src/components/AddScreen.js b/outloud/src/components/AddScreen.js
new file mode 100644
index 0000000..b316475
--- /dev/null
+++ b/outloud/src/components/AddScreen.js
@@ -0,0 +1,19 @@
+import React, {Component} from 'react';
+import {
+ View
+} from 'react-native';
+import { Button } from 'react-native-material-ui';
+
+class AddScreen extends Component {
+ render() {
+ return (
+
+
+ )
+ }
+}
+
+export default AddScreen;
\ No newline at end of file
diff --git a/outloud/src/components/CategoriesScreen.js b/outloud/src/components/CategoriesScreen.js
new file mode 100644
index 0000000..f6ab323
--- /dev/null
+++ b/outloud/src/components/CategoriesScreen.js
@@ -0,0 +1,54 @@
+import React, {Component} from 'react';
+import { View } from 'react-native';
+import { Button } from 'react-native-material-ui';
+import {api as apiConfig} from '../proxy.json';
+
+class CategoriesScreen extends Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ categories: []
+ }
+ }
+
+ getUrl = (endpoint) => {
+ if (__DEV__)
+ return `${apiConfig.dev}/${endpoint}`
+ else
+ return `${apiConfig.prod}/${endpoint}`
+ }
+
+ componentDidMount() {
+ apiUrl = this.getUrl('categories')
+ console.log(apiUrl)
+ try {
+ fetch(apiUrl)
+ .then(response => response.json())
+ .then(responseJson => {
+ let categories = []
+ responseJson.forEach(x => {
+ categories.push({id: x.id, name: x.name})
+ })
+ this.setState({categories: categories})
+ });
+ }
+ catch (ex) {
+ console.log(ex)
+ }
+ }
+
+ render() {
+ const {navigate} = this.props.navigation;
+ let categories = this.state.categories.map(x => (
+ navigate('Quizes', {parentId: x.id})} key={x.id}/>
+ ))
+
+ return(
+
+ {categories}
+
+ )
+ }
+}
+
+export default CategoriesScreen;
\ No newline at end of file
diff --git a/outloud/src/components/DetailScreen.js b/outloud/src/components/DetailScreen.js
index c2cd2e4..e457d0d 100644
--- a/outloud/src/components/DetailScreen.js
+++ b/outloud/src/components/DetailScreen.js
@@ -4,13 +4,12 @@ import {
View,
StyleSheet
} from 'react-native';
+import BottomNav from './navigation/BottomNav';
class DetailScreen extends Component {
render () {
return (
-
- Detail Screen
-
+
);
}
}
diff --git a/outloud/src/components/MainPage.js b/outloud/src/components/MainPage.js
index dd92fb9..0fc7ced 100644
--- a/outloud/src/components/MainPage.js
+++ b/outloud/src/components/MainPage.js
@@ -10,6 +10,7 @@ class MainPage extends Component {
this.props.navigation.navigate("Detail")} title="Detail Page" />
+ this.props.navigation.navigate("Categories")} title="Start" />
);
}
diff --git a/outloud/src/components/OfflineNotice.js b/outloud/src/components/OfflineNotice.js
index ba8d61a..f509c43 100644
--- a/outloud/src/components/OfflineNotice.js
+++ b/outloud/src/components/OfflineNotice.js
@@ -1,5 +1,14 @@
import React, { PureComponent } from 'react';
import { View, Text, NetInfo, Dimensions, StyleSheet } from 'react-native';
+import {api as apiConfig} from '../proxy.json';
+
+let apiUrl;
+
+if (__DEV__) {
+ apiUrl = apiConfig.dev + '/healthcheck';
+} else {
+ apiUrl = apiConfig.prod + '/healthcheck';
+}
const { width } = Dimensions.get('window');
@@ -10,10 +19,18 @@ function MiniOfflineSign() {
);
}
+function MiniServerDownSign() {
+ return (
+
+ No connection to the server
+
+ );
+}
class OfflineNotice extends PureComponent {
state = {
- isConnected: true
+ isConnected: true,
+ isHealthy: true
};
componentDidMount() {
@@ -30,12 +47,20 @@ class OfflineNotice extends PureComponent {
} else {
this.setState({ isConnected });
}
- };
+ try {
+ fetch(apiUrl).then(response => this.setState({isHealthy: response.ok}));
+ } catch(error) {
+ console.log(error);
+ this.setState({isHealthy: false})
+ }
+
+ }
render() {
- if (!this.state.isConnected) {
+ if (!this.state.isConnected)
return ;
- }
+ else if (!this.state.isHealthy)
+ return
return null;
}
}
@@ -51,6 +76,16 @@ const styles = StyleSheet.create({
position: 'absolute',
top: 0
},
+ downContainer: {
+ backgroundColor: '#cdb62c',
+ height: 30,
+ justifyContent: 'center',
+ alignItems: 'center',
+ flexDirection: 'row',
+ width,
+ position: 'absolute',
+ top: 0
+ },
offlineText: { color: '#fff' }
});
diff --git a/outloud/src/components/QuizData.js b/outloud/src/components/QuizData.js
index c2fb70c..337c341 100644
--- a/outloud/src/components/QuizData.js
+++ b/outloud/src/components/QuizData.js
@@ -1,63 +1,64 @@
import React, { Component } from "react";
import {AsyncStorage, Button, Text, View} from "react-native";
+import {api as apiConfig} from '../proxy.json';
let apiUrl;
if (__DEV__) {
- apiUrl = 'http://10.0.2.2:5002/api/values';
+ apiUrl = apiConfig.dev + '/api/values';
} else {
- apiUrl = 'http://outloud.azurewebsites.net/api/values';
+ apiUrl = apiConfig.prod + '/api/values';
}
class Quiz extends Component {
- state = {status: 0}
-
- saveData = async() => {
- try {
- let token = await AsyncStorage.getItem(`@User:accessToken`);
- console.log(token);
- let response = await fetch(apiUrl, {
- method: 'POST',
- headers: {
- 'Authorization': 'Bearer ' + token,
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- value: 'data'
- })
- });
- let responseResult = await response;
- console.log(responseResult);
- this.setState({status: responseResult.status})
- } catch (error) {
- console.error(error);
- }
- }
-
- render() {
- let message = '';
- if (this.state.status === 0)
- message = 'Not called'
- else if (this.state.status === 202)
- message = 'Accepted';
- else if (this.state.status === 401)
- message = 'Unauthorized'
- else
- message = 'Internal Server Error'
- return(
-
- {message}
-
-
- )
+ state = {status: 0}
+
+ saveData = async() => {
+ try {
+ let token = await AsyncStorage.getItem(`@User:accessToken`);
+ console.log(token);
+ console.log(apiUrl);
+ let response = await fetch(apiUrl, {
+ method: 'POST',
+ headers: {
+ 'Authorization': 'Bearer ' + token,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ value: 'data'
+ })
+ });
+ let responseResult = await response;
+ console.log(responseResult);
+ this.setState({status: responseResult.status})
+ } catch (error) {
+ console.error(error);
}
+ }
+ render() {
+ let message = '';
+ if (this.state.status === 0)
+ message = 'Not called'
+ else if (this.state.status === 202)
+ message = 'Accepted';
+ else if (this.state.status === 401)
+ message = 'Unauthorized'
+ else
+ message = 'Internal Server Error'
+ return(
+
+ {message}
+
+
+ )
+ }
}
export default class QuizData extends Component {
- render() {
- return(
-
- )
- }
+ render() {
+ return(
+
+ )
+ }
}
\ No newline at end of file
diff --git a/outloud/src/components/QuizesScreen.js b/outloud/src/components/QuizesScreen.js
new file mode 100644
index 0000000..7ef2755
--- /dev/null
+++ b/outloud/src/components/QuizesScreen.js
@@ -0,0 +1,57 @@
+import React, {Component} from 'react';
+import { View } from 'react-native';
+import { Button } from 'react-native-material-ui';
+import {api as apiConfig} from '../proxy.json';
+
+class QuizesScreen extends Component {
+ constructor(props) {
+ console.log(props)
+ super(props)
+ this.state = {
+ quizes: [],
+ parentId: props.navigation.state.params.parentId
+ }
+ }
+
+ getUrl = (endpoint) => {
+ if (__DEV__)
+ return `${apiConfig.dev}/${endpoint}`
+ else
+ return `${apiConfig.prod}/${endpoint}`
+ }
+
+ componentDidMount() {
+ apiUrl = this.getUrl(`quizes/${this.state.parentId}`)
+ try {
+ fetch(apiUrl)
+ .then(response => response.json())
+ .then(responseJson => {
+ let quizes = []
+ console.log(apiUrl)
+ responseJson.forEach(x => {
+ quizes.push({id: x.id, name: x.name})
+ })
+ this.setState({quizes: quizes})
+ });
+ }
+ catch (ex) {
+ console.log(ex)
+ }
+ }
+
+ render() {
+ console.log(this.state.quizes)
+ const {navigate} = this.props.navigation;
+ let quizes = this.state.quizes.map(x => (
+ navigate('Record', {parentId: x.id})} key={x.id}/>
+ ))
+ console.log(this.state.categories)
+ return(
+
+ {quizes}
+
+ )
+ }
+}
+
+export default QuizesScreen;
\ No newline at end of file
diff --git a/outloud/src/components/navigation/BottomNav.js b/outloud/src/components/navigation/BottomNav.js
new file mode 100644
index 0000000..d6ece39
--- /dev/null
+++ b/outloud/src/components/navigation/BottomNav.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import {View} from 'react-native';
+import Icon from 'react-native-vector-icons/MaterialIcons';
+import BottomNavigation, {
+ FullTab
+} from 'react-native-material-bottom-navigation'
+
+export default class BottomNav extends React.Component {
+ tabs = [
+ {
+ key: 'games',
+ icon: 'gamepad-variant',
+ label: 'Games',
+ barColor: '#388E3C',
+ pressColor: 'rgba(255, 255, 255, 0.16)'
+ },
+ {
+ key: 'movies-tv',
+ icon: 'movie',
+ label: 'Movies & TV',
+ barColor: '#B71C1C',
+ pressColor: 'rgba(255, 255, 255, 0.16)'
+ },
+ {
+ key: 'music',
+ icon: 'music-note',
+ label: 'Music',
+ barColor: '#E64A19',
+ pressColor: 'rgba(255, 255, 255, 0.16)'
+ }
+ ]
+
+ renderIcon = icon => ({ isActive }) => (
+
+ )
+
+ renderTab = ({ tab, isActive }) => (
+
+ )
+
+ render() {
+ return (
+
+
+ {/* Your screen contents depending on current tab. */}
+
+ this.setState({ activeTab: newTab.key })}
+ renderTab={this.renderTab}
+ tabs={this.tabs}
+ />
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/outloud/src/components/navigation/SideMenu.js b/outloud/src/components/navigation/SideMenu.js
index ba34174..9b6dabe 100644
--- a/outloud/src/components/navigation/SideMenu.js
+++ b/outloud/src/components/navigation/SideMenu.js
@@ -2,62 +2,111 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react';
import styles from './SideMenu.style';
import {NavigationActions} from 'react-navigation';
-import {ScrollView, Text, View} from 'react-native';
+import {AsyncStorage, ScrollView, Text, View} from 'react-native';
import LoginButton from '../LoginButton'
+import Auth0 from 'react-native-auth0';
+import {auth0 as auth0config} from '../../configuration.json';
+import {api as apiConfig} from '../../proxy.json';
+
+var jwtDecode = require('jwt-decode');
+
+const auth0 = new Auth0({
+ domain: auth0config.domain,
+ clientId: auth0config.clientId
+})
class SideMenu extends Component {
constructor(props) {
- super(props);
+ super(props)
+ this.state = {
+ isLogged: false,
+ userId: '',
+ courses: [],
+ }
+ this.checkProfile()
+ }
+
+ getUrl = (endpoint) => {
+ if (__DEV__)
+ return `${apiConfig.dev}/${endpoint}`
+ else
+ return `${apiConfig.prod}/${endpoint}`
+ }
+
+ getProfile = async() => {
+ let userId = await this.decodeToken()
+ let apiUrl = this.getUrl('users')
+ console.log(apiUrl)
+ try {
+ const res = await fetch(`${apiUrl}/${userId}`)
+ const json = await res.json();
+ console.log(json)
+ this.setState({
+ userId: json.id,
+ courses: json.courses,
+ })
+ } catch (ex) {
+ console.log(ex)
+ }
+ }
+
+ checkProfile = () => {
+ this.isAuthenticated().then(result => {
+ this.setState({isLogged: result})
+ this.getProfile().then(res => {
+ this.setState({profile: res})
+ })
+ })
+ }
+
+ isAuthenticated = async() => {
+ const expiresAt = await AsyncStorage.getItem(`@User:expiresAt`)
+ if (expiresAt == null)
+ return false;
+ const parsedExpireAt = JSON.parse(expiresAt)
+ return new Date().getTime() < parsedExpireAt
+ }
+
+ decodeToken = async() => {
+ const token = await AsyncStorage.getItem(`@User:accessToken`)
+ let decodedToken = jwtDecode(token)
+ return decodedToken.sub
+ }
+
+ print = async() => {
+ await this.decodeToken()
}
- navigateToScreen = (route) => () => {
+ navigateToScreen = (route,params) => () => {
const navigateAction = NavigationActions.navigate({
- routeName: route
- });
- this.props.navigation.dispatch(navigateAction);
+ routeName: route,
+ params: params
+ })
+ this.props.navigation.dispatch(navigateAction)
+ this.checkProfile()
}
render () {
+ let courses = this.state.courses.map(item => (
+
+
+ {item.displayName} {item.progress}
+
+
+ ))
return (
-
- Section 1
-
-
-
- Page1
-
-
-
-
-
- Section 2
-
-
-
- Page2
-
-
- Page3
-
-
-
-
-
- Section 3
+
+ Add
-
-
- Page4
-
-
+ {this.state.isLogged ? courses : Login to see your courses!}
- This is my fixed footer
+ Outloud
);
diff --git a/outloud/src/components/navigation/StackNav.js b/outloud/src/components/navigation/StackNav.js
index f0937bf..d483f81 100644
--- a/outloud/src/components/navigation/StackNav.js
+++ b/outloud/src/components/navigation/StackNav.js
@@ -1,25 +1,67 @@
import React from 'react';
import {TouchableOpacity} from 'react-native';
import {createDrawerNavigator} from 'react-navigation';
-import Icon from "react-native-vector-icons/MaterialIcons";
-import MainScreen from "../MainPage";
-import DetailScreen from "../DetailScreen";
+import Icon from 'react-native-vector-icons/MaterialIcons';
+import MainScreen from '../MainPage';
+import AddScreen from '../AddScreen';
+import ModifyItemScreen from '../quiz/ModifyItemScreen'
+import DetailScreen from '../DetailScreen';
+import CategoriesScreen from '../CategoriesScreen';
+import QuizesScreen from '../QuizesScreen';
+import Recognizer from '../speech/Recognizer';
+import BottomNav from './BottomNav';
const StackNav = createDrawerNavigator({
Main : {
screen: MainScreen,
navigationOptions: ({navigation}) => ({
- title: "Main",
- headerLeft:( navigation.navigate("DrawerOpen")}>
-
-
- )
+ title: 'Main',
+ headerLeft:
+ navigation.navigate('DrawerOpen')}>
+
+
})
},
+ BottomNav : {
+ screen: BottomNav,
+ navigationOptions: {
+ title: 'BottomNav'
+ }
+ },
+ Categories: {
+ screen: CategoriesScreen,
+ navigationOptions: {
+ title: 'Categories',
+ }
+ },
+ Quizes: {
+ screen: QuizesScreen,
+ navigationOptions: {
+ title: 'Quizes',
+ }
+ },
Detail: {
screen: DetailScreen,
navigationOptions: {
- title: "Detail",
+ title: 'Detail',
+ }
+ },
+ Record: {
+ screen: Recognizer,
+ navigationOptions: {
+ title: 'Record',
+ }
+ },
+ Add: {
+ screen: AddScreen,
+ navigationOptions: {
+ title: 'Add'
+ }
+ },
+ ModifyItem: {
+ screen: ModifyItemScreen,
+ navigationOptions: {
+ title: 'ModifyItem'
}
}
});
diff --git a/outloud/src/components/quiz/ModifyItemScreen.js b/outloud/src/components/quiz/ModifyItemScreen.js
new file mode 100644
index 0000000..05abbf0
--- /dev/null
+++ b/outloud/src/components/quiz/ModifyItemScreen.js
@@ -0,0 +1,163 @@
+import React, { Component } from 'react';
+import {
+ Modal,
+ View
+} from 'react-native';
+import { ActionButton, Button, Toolbar } from 'react-native-material-ui';
+import { TextField } from 'react-native-material-textfield';
+import { Dropdown } from 'react-native-material-dropdown';
+import {api as apiConfig} from '../../proxy.json';
+
+class ModifyItemScreen extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ items: [],
+ itemType: this.props.navigation.state.params.itemType,
+ modalVisible: false,
+ }
+ }
+
+ getUrl(itemType) {
+ if (__DEV__)
+ return `${apiConfig.dev}/${itemType}`;
+ else
+ return `${apiConfig.prod}/${itemType}`;
+ }
+
+ getNextItemType(itemType) {
+ if (!itemType)
+ return 'category'
+ if (itemType == 'category')
+ return 'quiz'
+ if (itemType == 'quiz')
+ return 'words'
+ }
+
+ getPreviousItemType(itemType) {
+ if (!itemType)
+ return 'words'
+ if (itemType == 'words')
+ return 'quiz'
+ if (itemType == 'quiz')
+ return 'category'
+ }
+
+ componentWillMount() {
+ this.load(null);
+ }
+
+ load(id) {
+ if (this.state.itemType) {
+ let apiUrl = this.getUrl(this.state.itemType)
+ if (id)
+ apiUrl += `/${id}`
+ console.log(apiUrl);
+ let nextItemType = this.getNextItemType(this.state.itemType);
+ try {
+ fetch(apiUrl)
+ .then(response => response.json())
+ .then(responseJson => {
+ this.setState({
+ items: responseJson,
+ itemType: nextItemType
+ })
+ });
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ }
+
+ loadPrevious = () => {
+ if (this.state.parentId)
+ this.load(this.parentId)
+ else
+ this.props.navigation.goBack()
+ }
+
+ setModalVisible(visible) {
+ this.setState({modalVisible: visible});
+ }
+
+ addNewItem(newItem) {
+ let itemType = this.getPreviousItemType(this.state.itemType)
+ if (itemType == 'category')
+ //dont render
+ if (itemType == 'quiz')
+ //render 1 dropdown
+ if (itemType == 'words')
+ //render 2 dropdowns
+
+ console.log("IMPLEMENT!")
+ }
+
+ render() {
+ let buttonItems;
+ let newItem;
+ let data = [{
+ value: 'Banana',
+ }, {
+ value: 'Mango',
+ }, {
+ value: 'Pear',
+ }];
+ const itemType = this.getPreviousItemType(this.state.itemType)
+ console.log(this.state.items.length)
+ if (this.state.items.length)
+ buttonItems = this.state.items.map(item => (
+ this.load(item.id)} key={item.id}/>
+ ));
+
+ return (
+
+ this.loadPrevious()}
+ onRightElementPress={ (label) => { console.log(label) }}
+ />
+ {buttonItems}
+ {
+ this.setModalVisible(false)
+ }}>
+
+ this.setModalVisible(false)}
+ centerElement={`Add a new ${itemType}`}
+ />
+
+ this.setState({ newItem }) }
+ />
+
+
+
+
+ this.setModalVisible(true)}/>
+
+ )
+ }
+}
+
+export default ModifyItemScreen;
\ No newline at end of file
diff --git a/outloud/src/components/speech/Recognizer.js b/outloud/src/components/speech/Recognizer.js
new file mode 100644
index 0000000..4ca377b
--- /dev/null
+++ b/outloud/src/components/speech/Recognizer.js
@@ -0,0 +1,238 @@
+import React, {Component} from 'react';
+import {AsyncStorage, Image, View, Text, TouchableHighlight, StyleSheet} from 'react-native';
+import Voice from 'react-native-voice';
+import Snackbar from 'react-native-material-snackbar';
+import {api as apiConfig} from '../../proxy.json';
+
+var jwtDecode = require('jwt-decode');
+
+export default class Recognizer extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ recognized: false,
+ pitch: false,
+ error: false,
+ end: false,
+ started: false,
+ results: [],
+ partialResults: [],
+ words: [],
+ index: 0,
+ points: 0,
+ correct: true,
+ parentId: props.navigation.state.params.parentId,
+ progress: 0,
+ };
+ Voice.onSpeechStart = this.onSpeechStart.bind(this);
+ Voice.onSpeechEnd = this.onSpeechEnd.bind(this);
+ Voice.onSpeechRecognized = this.onSpeechRecognized.bind(this);
+ Voice.onSpeechResults = this.onSpeechResults.bind(this);
+ }
+
+ getUrl(endpoint) {
+ if (__DEV__)
+ return `${apiConfig.dev}/${endpoint}`;
+ else
+ return `${apiConfig.prod}/${endpoint}`;
+ }
+
+ componentWillMount() {
+ let apiUrl = this.getUrl(`words/${this.state.parentId}`)
+ try {
+ fetch(apiUrl)
+ .then(response => response.json())
+ .then(responseJson => {
+ let words = responseJson.map(x => x.name);
+ this.setState({words: words})
+ });
+ }
+ catch(ex) {
+ console.log(ex);
+ }
+ }
+
+ componentWillUnmount = async() => {
+ Voice.destroy().then(Voice.removeAllListeners);
+ await this.saveProgress();
+ }
+
+ onSpeechStart = (e) => {
+ this.setState({
+ started: true
+ });
+ }
+
+ onSpeechEnd = (e) => {
+ this.setState({
+ end: true
+ });
+ }
+
+ onSpeechRecognized = (e) => {
+ this.setState({
+ recognized: true
+ });
+ }
+
+ onSpeechResults = (e) => {
+ this.setState({
+ results: e.value
+ });
+ console.log(this.state.results)
+ this.compareResults()
+ }
+
+ showPopup = (success) => {
+ let title = 'Correct'
+ let actionTitle = 'yas babe'
+ let color = 'green'
+
+ if (success === 1) {
+ title = 'U wrong n00b'
+ actionTitle = 'OK :('
+ color = 'red'
+ }
+
+ if (success === 2) {
+ title = 'Almost'
+ actionTitle = 'Arghhh'
+ color = 'orange'
+ }
+
+ Snackbar.show({
+ title,
+ duration: Snackbar.LENGTH_SHORT,
+ action: {
+ title: actionTitle,
+ color,
+ onPress: () => { Snackbar.dismiss },
+ }
+ })
+ }
+
+ compareResults = () => {
+ let word = this.state.words[this.state.index];
+ if (this.state.results[0].toLowerCase() === word.toLowerCase())
+ this.showPopup(0)
+ else if (this.state.results[1].toLowerCase() === word.toLowerCase())
+ this.showPopup(2)
+ else {
+ this.showPopup(1)
+ this.setState({
+ correct: false,
+ })
+ }
+
+ let progress = (this.state.index + 1) / this.state.words.length
+ this.setState({
+ index: this.state.index + 1,
+ progress
+ })
+ }
+
+ saveProgress = async() => {
+ let progress = this.state.progress * 100
+ let userId = await this.decodeToken()
+ let apiUrl = this.getUrl('users')
+ let courseId = this.state.parentId;
+ let courseName = 'asdasd'
+ const token = await AsyncStorage.getItem(`@User:accessToken`)
+ let body = JSON.stringify({
+ userId: userId,
+ courseId: courseId,
+ courseName: courseName,
+ progress: progress
+ })
+ console.log(body)
+ try {
+ let response = await fetch(apiUrl, {
+ method: 'POST',
+ headers: {
+ // 'Authorization': 'Bearer ' + token,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: body
+ });
+ let responseResult = await response;
+ console.log(responseResult)
+ } catch(ex) {
+ console.log(ex)
+ }
+ }
+
+ decodeToken = async() => {
+ const token = await AsyncStorage.getItem(`@User:accessToken`)
+ let decodedToken = jwtDecode(token)
+ return decodedToken.sub
+ }
+
+ _startRecognizing = async(e) => {
+ this.setState({
+ started: true,
+ });
+ try {
+ await Voice.start('en-US');
+ } catch (e) {
+ console.error(e)
+ }
+ }
+
+ _stopRecognizing = async(e) => {
+ try {
+ await Voice.stop()
+ } catch (e) {
+ console.error(e)
+ }
+ }
+
+ render() {
+ let word = this.state.words[this.state.index]
+ return (
+
+ Progress: {this.state.progress * 100}%
+ Say: {word}
+
+
+
+
+
+ Stop Recognizing
+
+
+ {this.state.results.map((result, index) => {
+ return (
+
+ {result}
+
+ )
+ })}
+
+ )
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ button: {
+ width: 200,
+ height: 200,
+ },
+ action: {
+ textAlign: 'center',
+ color: '#0000FF',
+ marginVertical: 5,
+ fontWeight: 'bold',
+ },
+});
\ No newline at end of file
diff --git a/outloud/src/components/speech/VoiceTest.js b/outloud/src/components/speech/VoiceTest.js
new file mode 100644
index 0000000..fa91eb1
--- /dev/null
+++ b/outloud/src/components/speech/VoiceTest.js
@@ -0,0 +1,245 @@
+import React, { Component } from 'react';
+import {
+ StyleSheet,
+ Text,
+ View,
+ Image,
+ TouchableHighlight,
+} from 'react-native';
+
+import Voice from 'react-native-voice';
+
+export default class VoiceTest extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ recognized: '',
+ pitch: '',
+ error: '',
+ end: '',
+ started: '',
+ results: [],
+ partialResults: [],
+ };
+ Voice.onSpeechStart = this.onSpeechStart.bind(this);
+ Voice.onSpeechRecognized = this.onSpeechRecognized.bind(this);
+ Voice.onSpeechEnd = this.onSpeechEnd.bind(this);
+ Voice.onSpeechError = this.onSpeechError.bind(this);
+ Voice.onSpeechResults = this.onSpeechResults.bind(this);
+ Voice.onSpeechPartialResults = this.onSpeechPartialResults.bind(this);
+ Voice.onSpeechVolumeChanged = this.onSpeechVolumeChanged.bind(this);
+ }
+
+ componentWillUnmount() {
+ Voice.destroy().then(Voice.removeAllListeners);
+ }
+
+ onSpeechStart(e) {
+ this.setState({
+ started: '√',
+ });
+ }
+
+ onSpeechRecognized(e) {
+ this.setState({
+ recognized: '√',
+ });
+ }
+
+ onSpeechEnd(e) {
+ this.setState({
+ end: '√',
+ });
+ }
+
+ onSpeechError(e) {
+ this.setState({
+ error: JSON.stringify(e.error),
+ });
+ }
+
+ onSpeechResults(e) {
+ this.setState({
+ results: e.value,
+ });
+ }
+
+ onSpeechPartialResults(e) {
+ this.setState({
+ partialResults: e.value,
+ });
+ }
+
+ onSpeechVolumeChanged(e) {
+ this.setState({
+ pitch: e.value,
+ });
+ }
+
+ async _startRecognizing(e) {
+ this.setState({
+ recognized: '',
+ pitch: '',
+ error: '',
+ started: '',
+ results: [],
+ partialResults: [],
+ end: ''
+ });
+ try {
+ await Voice.start('en-US');
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
+ async _stopRecognizing(e) {
+ try {
+ await Voice.stop();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
+ async _cancelRecognizing(e) {
+ try {
+ await Voice.cancel();
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
+ async _destroyRecognizer(e) {
+ try {
+ await Voice.destroy();
+ } catch (e) {
+ console.error(e);
+ }
+ this.setState({
+ recognized: '',
+ pitch: '',
+ error: '',
+ started: '',
+ results: [],
+ partialResults: [],
+ end: ''
+ });
+ }
+
+ render() {
+ return (
+
+
+ Welcome to React Native Voice!
+
+
+ Press the button and start speaking.
+
+
+ {`Started: ${this.state.started}`}
+
+
+ {`Recognized: ${this.state.recognized}`}
+
+
+ {`Pitch: ${this.state.pitch}`}
+
+
+ {`Error: ${this.state.error}`}
+
+
+ Results
+
+ {this.state.results.map((result, index) => {
+ return (
+
+ {result}
+
+ )
+ })}
+
+ Partial Results
+
+ {this.state.partialResults.map((result, index) => {
+ return (
+
+ {result}
+
+ )
+ })}
+
+ {`End: ${this.state.end}`}
+
+
+
+
+
+
+ Stop Recognizing
+
+
+
+
+ Cancel
+
+
+
+
+ Destroy
+
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ button: {
+ width: 50,
+ height: 50,
+ },
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
+ },
+ welcome: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
+ },
+ action: {
+ textAlign: 'center',
+ color: '#0000FF',
+ marginVertical: 5,
+ fontWeight: 'bold',
+ },
+ instructions: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
+ },
+ stat: {
+ textAlign: 'center',
+ color: '#B0171F',
+ marginBottom: 1,
+ },
+});
\ No newline at end of file
diff --git a/outloud/src/proxy.json b/outloud/src/proxy.json
new file mode 100644
index 0000000..0fad085
--- /dev/null
+++ b/outloud/src/proxy.json
@@ -0,0 +1,6 @@
+{
+ "api": {
+ "dev": "http://localhost:5000", //10.0.2.2/localhost
+ "prod": "http://outloud.azurewebsites.net"
+ }
+}
\ No newline at end of file
diff --git a/run-device-as-host.sh b/run-device-as-host.sh
new file mode 100644
index 0000000..e25a03e
--- /dev/null
+++ b/run-device-as-host.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Run an emulator without running Android Studio (https://stackoverflow.com/questions/42718973/run-avd-emulator-without-android-studio)
+#1 start chrome for remote debugging
+start chrome "http://localhost:8081/debugger-ui/"
+#2 start emulator
+cd C:/Users/Marcin/AppData/Local/Android/Sdk/platform-tools
+./adb reverse tcp:8081 tcp:8081
+./adb reverse tcp:5002 tcp:5002
+./adb reverse tcp:5000 tcp:5000
\ No newline at end of file
diff --git a/run-emulator.sh b/run-emulator.sh
index 4a8c4d5..5288ffb 100755
--- a/run-emulator.sh
+++ b/run-emulator.sh
@@ -4,4 +4,4 @@
start chrome "http://localhost:8081/debugger-ui/"
#2 start emulator
cd C:/Users/Marcin/AppData/Local/Android/Sdk/tools
-./emulator -avd Nexus_5X_API_26 -feature WindowsHypervisorPlatform
\ No newline at end of file
+./emulator -avd Nexus_5X_API_26
\ No newline at end of file