@@ -21,7 +21,7 @@ node_modules/warning/.* | |||
[include] | |||
[libs] | |||
node_modules/react-native/Libraries/react-native/react-native-interface.js | |||
node_modules/react-native/interface.js | |||
node_modules/react-native/flow/ | |||
[options] | |||
@@ -36,9 +36,8 @@ module.file_ext=.ios.js | |||
munge_underscores=true | |||
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation' | |||
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1' | |||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub' | |||
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub' | |||
suppress_type=$FlowIssue | |||
suppress_type=$FlowFixMe | |||
@@ -72,4 +71,4 @@ untyped-import | |||
untyped-type-import | |||
[version] | |||
^0.105.0 | |||
^0.113.0 |
@@ -1 +1,2 @@ | |||
*.pbxproj -text | |||
# specific for windows script files | |||
*.bat text eol=crlf |
@@ -1,11 +1,4 @@ | |||
/** | |||
* Sample React Native App | |||
* https://github.com/facebook/react-native | |||
* | |||
* @format | |||
* @flow | |||
*/ | |||
import "react-native-gesture-handler"; | |||
import React from "react"; | |||
import { Provider } from "react-redux"; | |||
import { Provider as PaperProvider } from "react-native-paper"; | |||
@@ -15,7 +15,9 @@ import com.android.build.OutputFile | |||
* // the name of the generated asset file containing your JS bundle | |||
* bundleAssetName: "index.android.bundle", | |||
* | |||
* // the entry file for bundle generation | |||
* // the entry file for bundle generation. If none specified and | |||
* // "index.android.js" exists, it will be used. Otherwise "index.js" is | |||
* // default. Can be overridden with ENTRY_FILE environment variable. | |||
* entryFile: "index.android.js", | |||
* | |||
* // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format | |||
@@ -85,7 +87,6 @@ project.ext.vectoricons = [ | |||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" | |||
project.ext.react = [ | |||
entryFile: "index.js", | |||
enableHermes: false, // clean and rebuild if changing | |||
] | |||
@@ -177,6 +178,14 @@ android { | |||
signingConfig signingConfigs.release | |||
} | |||
} | |||
packagingOptions { | |||
pickFirst "lib/armeabi-v7a/libc++_shared.so" | |||
pickFirst "lib/arm64-v8a/libc++_shared.so" | |||
pickFirst "lib/x86/libc++_shared.so" | |||
pickFirst "lib/x86_64/libc++_shared.so" | |||
} | |||
// applicationVariants are e.g. debug, release | |||
applicationVariants.all { variant -> | |||
variant.outputs.each { output -> | |||
@@ -195,7 +204,23 @@ android { | |||
dependencies { | |||
implementation fileTree(dir: "libs", include: ["*.jar"]) | |||
//noinspection GradleDynamicVersion | |||
implementation "com.facebook.react:react-native:+" // From node_modules | |||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" | |||
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' | |||
} | |||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { | |||
exclude group:'com.facebook.flipper' | |||
} | |||
implementation "com.madgag.spongycastle:core:1.58.0.0" | |||
if (enableHermes) { | |||
def hermesPath = "../../node_modules/hermes-engine/android/"; | |||
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:tools="http://schemas.android.com/tools"> | |||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | |||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" /> | |||
</manifest> |
@@ -0,0 +1,72 @@ | |||
/** | |||
* Copyright (c) Facebook, Inc. and its affiliates. | |||
* | |||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root | |||
* directory of this source tree. | |||
*/ | |||
package com.lesspass.android; | |||
import android.content.Context; | |||
import com.facebook.flipper.android.AndroidFlipperClient; | |||
import com.facebook.flipper.android.utils.FlipperUtils; | |||
import com.facebook.flipper.core.FlipperClient; | |||
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; | |||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; | |||
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; | |||
import com.facebook.flipper.plugins.inspector.DescriptorMapping; | |||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; | |||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; | |||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; | |||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin; | |||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; | |||
import com.facebook.react.ReactInstanceManager; | |||
import com.facebook.react.bridge.ReactContext; | |||
import com.facebook.react.modules.network.NetworkingModule; | |||
import okhttp3.OkHttpClient; | |||
public class ReactNativeFlipper { | |||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { | |||
if (FlipperUtils.shouldEnableFlipper(context)) { | |||
final FlipperClient client = AndroidFlipperClient.getInstance(context); | |||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); | |||
client.addPlugin(new ReactFlipperPlugin()); | |||
client.addPlugin(new DatabasesFlipperPlugin(context)); | |||
client.addPlugin(new SharedPreferencesFlipperPlugin(context)); | |||
client.addPlugin(CrashReporterPlugin.getInstance()); | |||
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); | |||
NetworkingModule.setCustomClientBuilder( | |||
new NetworkingModule.CustomClientBuilder() { | |||
@Override | |||
public void apply(OkHttpClient.Builder builder) { | |||
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); | |||
} | |||
}); | |||
client.addPlugin(networkFlipperPlugin); | |||
client.start(); | |||
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized | |||
// Hence we run if after all native modules have been initialized | |||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); | |||
if (reactContext == null) { | |||
reactInstanceManager.addReactInstanceEventListener( | |||
new ReactInstanceManager.ReactInstanceEventListener() { | |||
@Override | |||
public void onReactContextInitialized(ReactContext reactContext) { | |||
reactInstanceManager.removeReactInstanceEventListener(this); | |||
reactContext.runOnNativeModulesQueueThread( | |||
new Runnable() { | |||
@Override | |||
public void run() { | |||
client.addPlugin(new FrescoFlipperPlugin()); | |||
} | |||
}); | |||
} | |||
}); | |||
} else { | |||
client.addPlugin(new FrescoFlipperPlugin()); | |||
} | |||
} | |||
} | |||
} |
@@ -19,7 +19,8 @@ | |||
<activity | |||
android:name=".MainActivity" | |||
android:label="@string/app_name" | |||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" | |||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" | |||
android:launchMode="singleTask" | |||
android:windowSoftInputMode="adjustResize"> | |||
<intent-filter> | |||
<action android:name="android.intent.action.MAIN" /> | |||
@@ -4,6 +4,7 @@ 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; | |||
@@ -42,23 +43,28 @@ public class MainApplication extends Application implements ReactApplication { | |||
public void onCreate() { | |||
super.onCreate(); | |||
SoLoader.init(this, /* native exopackage */ false); | |||
initializeFlipper(this); // Remove this line if you don't want Flipper enabled | |||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); | |||
} | |||
/** | |||
* Loads Flipper in React Native templates. | |||
* 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) { | |||
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("com.facebook.flipper.ReactNativeFlipper"); | |||
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context); | |||
Class<?> aClass = Class.forName("com.lesspass.android.ReactNativeFlipper"); | |||
aClass | |||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) | |||
.invoke(null, context, reactInstanceManager); | |||
} catch (ClassNotFoundException e) { | |||
e.printStackTrace(); | |||
} catch (NoSuchMethodException e) { | |||
@@ -70,4 +76,4 @@ public class MainApplication extends Application implements ReactApplication { | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -7,7 +7,7 @@ buildscript { | |||
jcenter() | |||
} | |||
dependencies { | |||
classpath("com.android.tools.build:gradle:3.4.2") | |||
classpath("com.android.tools.build:gradle:3.5.2") | |||
// NOTE: Do not place your application dependencies here; they belong | |||
// in the individual module build.gradle files | |||
@@ -28,7 +28,7 @@ allprojects { | |||
google() | |||
jcenter() | |||
maven { url 'https://jitpack.io' } | |||
maven { url 'https://www.jitpack.io' } | |||
} | |||
} | |||
@@ -17,5 +17,12 @@ | |||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | |||
# org.gradle.parallel=true | |||
# AndroidX package structure to make it clearer which packages are bundled with the | |||
# Android operating system, and which are packaged with your app's APK | |||
# https://developer.android.com/topic/libraries/support-library/androidx-rn | |||
android.useAndroidX=true | |||
# Automatically convert third-party libraries to use AndroidX | |||
android.enableJetifier=true | |||
# Version of flipper SDK to use with React Native | |||
FLIPPER_VERSION=0.33.1 |
@@ -1,5 +1,5 @@ | |||
distributionBase=GRADLE_USER_HOME | |||
distributionPath=wrapper/dists | |||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip | |||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip | |||
zipStoreBase=GRADLE_USER_HOME | |||
zipStorePath=wrapper/dists |
@@ -7,7 +7,7 @@ | |||
# you may not use this file except in compliance with the License. | |||
# You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# 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, | |||
@@ -125,8 +125,8 @@ if $darwin; then | |||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||
fi | |||
# For Cygwin, switch paths to Windows format before running java | |||
if $cygwin ; then | |||
# 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"` | |||
@@ -1,9 +1,9 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<Scheme | |||
LastUpgradeVersion = "0940" | |||
LastUpgradeVersion = "1130" | |||
version = "1.3"> | |||
<BuildAction | |||
parallelizeBuildables = "NO" | |||
parallelizeBuildables = "YES" | |||
buildImplicitDependencies = "YES"> | |||
<BuildActionEntries> | |||
<BuildActionEntry | |||
@@ -14,40 +14,12 @@ | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "2D2A28121D9B038B00D4039D" | |||
BuildableName = "libReact.a" | |||
BlueprintName = "React-tvOS" | |||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
<BuildActionEntry | |||
buildForTesting = "YES" | |||
buildForRunning = "YES" | |||
buildForProfiling = "YES" | |||
buildForArchiving = "YES" | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||
BuildableName = "LessPass-tvOS.app" | |||
BlueprintName = "LessPass-tvOS" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
<BuildActionEntry | |||
buildForTesting = "YES" | |||
buildForRunning = "YES" | |||
buildForProfiling = "NO" | |||
buildForArchiving = "NO" | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7" | |||
BuildableName = "LessPass-tvOSTests.xctest" | |||
BlueprintName = "LessPass-tvOSTests" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
</BuildActionEntries> | |||
</BuildAction> | |||
<TestAction | |||
@@ -67,17 +39,6 @@ | |||
</BuildableReference> | |||
</TestableReference> | |||
</Testables> | |||
<MacroExpansion> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||
BuildableName = "LessPass-tvOS.app" | |||
BlueprintName = "LessPass-tvOS" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</MacroExpansion> | |||
<AdditionalOptions> | |||
</AdditionalOptions> | |||
</TestAction> | |||
<LaunchAction | |||
buildConfiguration = "Debug" | |||
@@ -99,8 +60,6 @@ | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildableProductRunnable> | |||
<AdditionalOptions> | |||
</AdditionalOptions> | |||
</LaunchAction> | |||
<ProfileAction | |||
buildConfiguration = "Release" | |||
@@ -1,9 +1,9 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<Scheme | |||
LastUpgradeVersion = "0940" | |||
LastUpgradeVersion = "1130" | |||
version = "1.3"> | |||
<BuildAction | |||
parallelizeBuildables = "NO" | |||
parallelizeBuildables = "YES" | |||
buildImplicitDependencies = "YES"> | |||
<BuildActionEntries> | |||
<BuildActionEntry | |||
@@ -14,40 +14,12 @@ | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192" | |||
BuildableName = "libReact.a" | |||
BlueprintName = "React" | |||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
<BuildActionEntry | |||
buildForTesting = "YES" | |||
buildForRunning = "YES" | |||
buildForProfiling = "YES" | |||
buildForArchiving = "YES" | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||
BuildableName = "LessPass.app" | |||
BlueprintName = "LessPass" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
<BuildActionEntry | |||
buildForTesting = "YES" | |||
buildForRunning = "YES" | |||
buildForProfiling = "NO" | |||
buildForArchiving = "NO" | |||
buildForAnalyzing = "YES"> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "00E356ED1AD99517003FC87E" | |||
BuildableName = "LessPassTests.xctest" | |||
BlueprintName = "LessPassTests" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildActionEntry> | |||
</BuildActionEntries> | |||
</BuildAction> | |||
<TestAction | |||
@@ -67,17 +39,6 @@ | |||
</BuildableReference> | |||
</TestableReference> | |||
</Testables> | |||
<MacroExpansion> | |||
<BuildableReference | |||
BuildableIdentifier = "primary" | |||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||
BuildableName = "LessPass.app" | |||
BlueprintName = "LessPass" | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</MacroExpansion> | |||
<AdditionalOptions> | |||
</AdditionalOptions> | |||
</TestAction> | |||
<LaunchAction | |||
buildConfiguration = "Debug" | |||
@@ -99,8 +60,6 @@ | |||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||
</BuildableReference> | |||
</BuildableProductRunnable> | |||
<AdditionalOptions> | |||
</AdditionalOptions> | |||
</LaunchAction> | |||
<ProfileAction | |||
buildConfiguration = "Release" | |||
@@ -1,10 +1,3 @@ | |||
/** | |||
* Copyright (c) Facebook, Inc. and its affiliates. | |||
* | |||
* This source code is licensed under the MIT license found in the | |||
* LICENSE file in the root directory of this source tree. | |||
*/ | |||
#import <React/RCTBridgeDelegate.h> | |||
#import <UIKit/UIKit.h> | |||
@@ -1,20 +1,36 @@ | |||
/** | |||
* Copyright (c) Facebook, Inc. and its affiliates. | |||
* | |||
* This source code is licensed under the MIT license found in the | |||
* LICENSE file in the root directory of this source tree. | |||
*/ | |||
#import "AppDelegate.h" | |||
#import <React/RCTBridge.h> | |||
#import <React/RCTBundleURLProvider.h> | |||
#import <React/RCTRootView.h> | |||
#if DEBUG | |||
#import <FlipperKit/FlipperClient.h> | |||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h> | |||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h> | |||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h> | |||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h> | |||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h> | |||
static void InitializeFlipper(UIApplication *application) { | |||
FlipperClient *client = [FlipperClient sharedClient]; | |||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; | |||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; | |||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; | |||
[client addPlugin:[FlipperKitReactPlugin new]]; | |||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; | |||
[client start]; | |||
} | |||
#endif | |||
@implementation AppDelegate | |||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |||
{ | |||
#if DEBUG | |||
InitializeFlipper(application); | |||
#endif | |||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; | |||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge | |||
moduleName:@"LessPass" | |||
@@ -1,10 +1,3 @@ | |||
/** | |||
* Copyright (c) Facebook, Inc. and its affiliates. | |||
* | |||
* This source code is licensed under the MIT license found in the | |||
* LICENSE file in the root directory of this source tree. | |||
*/ | |||
#import <UIKit/UIKit.h> | |||
#import "AppDelegate.h" | |||
@@ -1,10 +1,3 @@ | |||
/** | |||
* Copyright (c) Facebook, Inc. and its affiliates. | |||
* | |||
* This source code is licensed under the MIT license found in the | |||
* LICENSE file in the root directory of this source tree. | |||
*/ | |||
#import <UIKit/UIKit.h> | |||
#import <XCTest/XCTest.h> | |||
@@ -59,7 +52,6 @@ | |||
return NO; | |||
}]; | |||
} | |||
#ifdef DEBUG | |||
RCTSetLogFunction(RCTDefaultLogFunction); | |||
#endif | |||
@@ -1,6 +1,49 @@ | |||
platform :ios, '9.0' | |||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' | |||
def add_flipper_pods!(versions = {}) | |||
versions['Flipper'] ||= '~> 0.33.1' | |||
versions['DoubleConversion'] ||= '1.1.7' | |||
versions['Flipper-Folly'] ||= '~> 2.1' | |||
versions['Flipper-Glog'] ||= '0.3.6' | |||
versions['Flipper-PeerTalk'] ||= '~> 0.0.4' | |||
versions['Flipper-RSocket'] ||= '~> 1.0' | |||
pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug' | |||
# List all transitive dependencies for FlipperKit pods | |||
# to avoid them being linked in Release builds | |||
pod 'Flipper', versions['Flipper'], :configuration => 'Debug' | |||
pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug' | |||
pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug' | |||
pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug' | |||
pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug' | |||
pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug' | |||
pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug' | |||
pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug' | |||
end | |||
# Post Install processing for Flipper | |||
def flipper_post_install(installer) | |||
installer.pods_project.targets.each do |target| | |||
if target.name == 'YogaKit' | |||
target.build_configurations.each do |config| | |||
config.build_settings['SWIFT_VERSION'] = '4.1' | |||
end | |||
end | |||
end | |||
end | |||
target 'LessPass' do | |||
# Pods for LessPass | |||
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" | |||
@@ -26,20 +69,29 @@ target 'LessPass' do | |||
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' | |||
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' | |||
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' | |||
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" | |||
pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" | |||
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" | |||
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' | |||
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true | |||
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' | |||
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' | |||
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' | |||
target 'LessPassTests' do | |||
inherit! :search_paths | |||
inherit! :complete | |||
# Pods for testing | |||
end | |||
use_native_modules! | |||
# Enables Flipper. | |||
# | |||
# Note that if you have use_frameworks! enabled, Flipper will not work and | |||
# you should disable these next few lines. | |||
add_flipper_pods! | |||
post_install do |installer| | |||
flipper_post_install(installer) | |||
end | |||
end | |||
target 'LessPass-tvOS' do | |||
@@ -49,5 +101,4 @@ target 'LessPass-tvOS' do | |||
inherit! :search_paths | |||
# Pods for testing | |||
end | |||
end |
@@ -18,37 +18,42 @@ | |||
"postinstall": "node ./scripts/postInstall.js" | |||
}, | |||
"dependencies": { | |||
"@react-native-community/async-storage": "^1.6.2", | |||
"axios": "^0.19.0", | |||
"@react-native-community/async-storage": "^1.9.0", | |||
"@react-native-community/masked-view": "^0.1.9", | |||
"@react-navigation/bottom-tabs": "^5.2.6", | |||
"@react-navigation/material-bottom-tabs": "^5.1.8", | |||
"@react-navigation/native": "^5.1.5", | |||
"@react-navigation/stack": "^5.2.10", | |||
"axios": "^0.19.2", | |||
"fuse.js": "^3.4.5", | |||
"lesspass-fingerprint": "latest", | |||
"lesspass-render-password": "latest", | |||
"lesspass-fingerprint": "^9.1.4", | |||
"lesspass-render-password": "^9.1.4", | |||
"lodash": "^4.17.15", | |||
"memoize-one": "^5.1.1", | |||
"react": "16.9.0", | |||
"react-native": "0.61.2", | |||
"react-native-gesture-handler": "^1.4.1", | |||
"react": "16.11.0", | |||
"react-native": "0.62.2", | |||
"react-native-gesture-handler": "^1.6.1", | |||
"react-native-keychain": "^4.0.1", | |||
"react-native-paper": "^3.0.0", | |||
"react-native-paper": "^3.8.0", | |||
"react-native-reanimated": "^1.8.0", | |||
"react-native-safe-area-context": "^0.7.3", | |||
"react-native-screens": "^2.4.0", | |||
"react-native-touch-id": "^4.4.1", | |||
"react-native-vector-icons": "^6.6.0", | |||
"react-navigation": "^4.0.10", | |||
"react-navigation-material-bottom-tabs": "^2.1.3", | |||
"react-navigation-stack": "^1.10.2", | |||
"react-redux": "^7.1.1", | |||
"redux": "^4.0.4", | |||
"react-redux": "^7.2.0", | |||
"redux": "^4.0.5", | |||
"redux-persist": "^6.0.0", | |||
"redux-thunk": "^2.3.0" | |||
}, | |||
"devDependencies": { | |||
"@babel/core": "^7.6.4", | |||
"@babel/runtime": "^7.6.3", | |||
"@react-native-community/eslint-config": "^0.0.5", | |||
"babel-jest": "^24.9.0", | |||
"eslint": "^6.5.1", | |||
"jest": "^24.9.0", | |||
"metro-react-native-babel-preset": "^0.56.0", | |||
"react-test-renderer": "16.9.0" | |||
"@babel/core": "^7.9.0", | |||
"@babel/runtime": "^7.9.2", | |||
"@react-native-community/eslint-config": "^1.0.0", | |||
"babel-jest": "^25.3.0", | |||
"eslint": "^6.8.0", | |||
"jest": "^25.3.0", | |||
"metro-react-native-babel-preset": "^0.59.0", | |||
"react-test-renderer": "16.13.1" | |||
}, | |||
"jest": { | |||
"preset": "react-native" | |||
@@ -1,86 +1,69 @@ | |||
import React from "react"; | |||
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs"; | |||
import * as React from "react"; | |||
import { useSelector } from "react-redux"; | |||
import { NavigationContainer } from "@react-navigation/native"; | |||
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; | |||
import Icon from "react-native-vector-icons/FontAwesome"; | |||
import { createAppContainer, createSwitchNavigator } from "react-navigation"; | |||
import AuthStack from "./auth/AuthStack"; | |||
import AuthLoadingScreen from "./auth/AuthLoadingScreen"; | |||
import HelpScreen from "./help/HelpScreen"; | |||
import Theme from "./ui/Theme"; | |||
import LoadingScreen from "./ui/LoadingScreen"; | |||
import PasswordGeneratorScreen from "./password/PasswordGeneratorScreen"; | |||
import SettingsScreen from "./settings/SettingsScreen"; | |||
import Theme from "./ui/Theme"; | |||
const commonTabs = { | |||
PasswordGenerator: { | |||
screen: PasswordGeneratorScreen, | |||
navigationOptions: { | |||
title: "LessPass", | |||
tabBarIcon: ({ tintColor }) => ( | |||
<Icon size={20} name="user-secret" style={{ color: tintColor }} /> | |||
) | |||
} | |||
}, | |||
Settings: { | |||
screen: SettingsScreen, | |||
navigationOptions: { | |||
title: "Settings", | |||
tabBarIcon: ({ tintColor }) => ( | |||
<Icon size={20} name="cogs" style={{ color: tintColor }} /> | |||
) | |||
} | |||
}, | |||
Help: { | |||
screen: HelpScreen, | |||
navigationOptions: { | |||
title: "Help", | |||
tabBarIcon: ({ tintColor }) => ( | |||
<Icon size={20} name="question" style={{ color: tintColor }} /> | |||
) | |||
} | |||
} | |||
}; | |||
import HelpScreen from "./help/HelpScreen"; | |||
import AuthStackScreen from "./auth/AuthStackScreen"; | |||
import SignOutScreen from "./auth/SignOutScreen"; | |||
import routes from "./routes"; | |||
const tabOptions = { | |||
initialRouteName: "PasswordGenerator", | |||
activeTintColor: Theme.colors.white, | |||
inactiveTintColor: Theme.colors.lightBlue, | |||
barStyle: { backgroundColor: Theme.colors.primary }, | |||
labeled: true | |||
}; | |||
const Tab = createBottomTabNavigator(); | |||
const AppNavigator = createMaterialBottomTabNavigator( | |||
{ | |||
...commonTabs | |||
}, | |||
tabOptions | |||
); | |||
function App() { | |||
const auth = useSelector((state) => state.auth); | |||
const AuthNavigator = createMaterialBottomTabNavigator( | |||
{ | |||
...commonTabs, | |||
SignIn: { | |||
screen: AuthStack, | |||
navigationOptions: { | |||
title: "Sign In", | |||
tabBarIcon: ({ tintColor }) => ( | |||
<Icon size={20} name="user" style={{ color: tintColor }} /> | |||
) | |||
} | |||
} | |||
}, | |||
tabOptions | |||
); | |||
if (auth.isLoading) { | |||
return <LoadingScreen />; | |||
} | |||
const AppContainer = createAppContainer( | |||
createSwitchNavigator( | |||
{ | |||
AuthLoading: AuthLoadingScreen, | |||
App: AppNavigator, | |||
Auth: AuthNavigator | |||
}, | |||
{ | |||
initialRouteName: "AuthLoading" | |||
} | |||
) | |||
); | |||
return ( | |||
<NavigationContainer> | |||
<Tab.Navigator | |||
screenOptions={({ route }) => ({ | |||
tabBarIcon: ({ color, size }) => { | |||
let iconName; | |||
if (route.name === routes.PASSWORD_GENERATOR) { | |||
iconName = "user-secret"; | |||
} else if (route.name === routes.SETTINGS) { | |||
iconName = "cogs"; | |||
} else if (route.name === routes.HELP) { | |||
iconName = "question"; | |||
} else if (route.name === routes.AUTH_STACK) { | |||
iconName = "user"; | |||
} else if (route.name === routes.SIGN_OUT) { | |||
iconName = "user"; | |||
} | |||
return ( | |||
<Icon size={size} name={iconName} style={{ color: color }} /> | |||
); | |||
}, | |||
})} | |||
tabBarOptions={{ | |||
activeTintColor: Theme.colors.white, | |||
activeBackgroundColor: Theme.colors.primary, | |||
inactiveTintColor: Theme.colors.lightBlue, | |||
inactiveBackgroundColor: Theme.colors.primary, | |||
}} | |||
> | |||
<Tab.Screen | |||
name={routes.PASSWORD_GENERATOR} | |||
component={PasswordGeneratorScreen} | |||
/> | |||
<Tab.Screen name={routes.SETTINGS} component={SettingsScreen} /> | |||
<Tab.Screen name={routes.HELP} component={HelpScreen} /> | |||
{auth.jwt == null ? ( | |||
<Tab.Screen name={routes.AUTH_STACK} component={AuthStackScreen} /> | |||
) : ( | |||
<Tab.Screen name={routes.SIGN_OUT} component={SignOutScreen} /> | |||
)} | |||
</Tab.Navigator> | |||
</NavigationContainer> | |||
); | |||
} | |||
export default AppContainer; | |||
export default App; |
@@ -1,31 +0,0 @@ | |||
import React, { Component } from "react"; | |||
import { connect } from "react-redux"; | |||
import { ActivityIndicator, View } from "react-native"; | |||
class AuthLoadingScreen extends Component { | |||
constructor(props) { | |||
super(props); | |||
this._bootstrapAsync(); | |||
} | |||
_bootstrapAsync = async () => { | |||
const { navigation, auth } = this.props; | |||
navigation.navigate(auth.jwt ? "App" : "Auth"); | |||
}; | |||
render() { | |||
return ( | |||
<View style={{ flex: 1, justifyContent: "center" }}> | |||
<ActivityIndicator size="large" color="#ffffff" /> | |||
</View> | |||
); | |||
} | |||
} | |||
function mapStateToProps(state) { | |||
return { | |||
auth: state.auth | |||
}; | |||
} | |||
export default connect(mapStateToProps)(AuthLoadingScreen); |
@@ -1,16 +0,0 @@ | |||
import { createStackNavigator } from "react-navigation-stack"; | |||
import SignInScreen from "./SignInScreen"; | |||
import SignUpScreen from "./SignUpScreen"; | |||
const AuthStack = createStackNavigator( | |||
{ | |||
SignIn: SignInScreen, | |||
SignUp: SignUpScreen | |||
}, | |||
{ | |||
initialRouteName: "SignIn", | |||
headerMode: "none" | |||
} | |||
); | |||
export default AuthStack; |
@@ -0,0 +1,15 @@ | |||
import React from "react"; | |||
import { createStackNavigator } from "@react-navigation/stack"; | |||
import SignInScreen from "./SignInScreen"; | |||
import SignUpScreen from "./SignUpScreen"; | |||
const AuthStack = createStackNavigator(); | |||
const AuthStackScreen = () => ( | |||
<AuthStack.Navigator headerMode="none"> | |||
<AuthStack.Screen name="SignIn" component={SignInScreen} /> | |||
<AuthStack.Screen name="SignUp" component={SignUpScreen} /> | |||
</AuthStack.Navigator> | |||
); | |||
export default AuthStackScreen; |
@@ -8,6 +8,7 @@ import TextInput from "../ui/TextInput"; | |||
import Styles from "../ui/Styles"; | |||
import { addError } from "../errors/errorsActions"; | |||
import { signIn } from "./authActions"; | |||
import routes from "../routes"; | |||
export class SignInScreen extends Component { | |||
constructor(props) { | |||
@@ -15,7 +16,7 @@ export class SignInScreen extends Component { | |||
this.state = { | |||
email: "", | |||
password: "", | |||
isLoading: false | |||
isLoading: false, | |||
}; | |||
} | |||
@@ -35,17 +36,13 @@ export class SignInScreen extends Component { | |||
mode="outlined" | |||
label="Email" | |||
value={email} | |||
onChangeText={text => this.setState({ email: text.trim() })} | |||
onChangeText={(text) => this.setState({ email: text.trim() })} | |||
/> | |||
<MasterPassword | |||
label={ | |||
encryptMasterPassword | |||
? "Master Password" | |||
: "Password" | |||
} | |||
label={encryptMasterPassword ? "Master Password" : "Password"} | |||
masterPassword={password} | |||
hideFingerprint={!encryptMasterPassword} | |||
onChangeText={password => this.setState({ password })} | |||
onChangeText={(password) => this.setState({ password })} | |||
/> | |||
<Button | |||
compact | |||
@@ -58,11 +55,11 @@ export class SignInScreen extends Component { | |||
signIn( | |||
{ | |||
email, | |||
password | |||
password, | |||
}, | |||
encryptMasterPassword | |||
) | |||
.then(() => navigation.navigate("App")) | |||
.then(() => navigation.navigate(routes.PASSWORD_GENERATOR)) | |||
.catch(() => { | |||
this.setState({ isLoading: false }); | |||
let errorMessage = | |||
@@ -83,7 +80,7 @@ export class SignInScreen extends Component { | |||
icon="account-circle" | |||
mode="outlined" | |||
style={Styles.loginSignUpButton} | |||
onPress={() => navigation.navigate("SignUp")} | |||
onPress={() => navigation.navigate(routes.SIGN_UP)} | |||
> | |||
Sign Up | |||
</Button> | |||
@@ -95,19 +92,16 @@ export class SignInScreen extends Component { | |||
function mapStateToProps(state) { | |||
return { | |||
settings: state.settings | |||
settings: state.settings, | |||
}; | |||
} | |||
function mapDispatchToProps(dispatch) { | |||
return { | |||
addError: message => dispatch(addError(message)), | |||
addError: (message) => dispatch(addError(message)), | |||
signIn: (credentials, encryptMasterPassword) => | |||
dispatch(signIn(credentials, encryptMasterPassword)) | |||
dispatch(signIn(credentials, encryptMasterPassword)), | |||
}; | |||
} | |||
export default connect( | |||
mapStateToProps, | |||
mapDispatchToProps | |||
)(SignInScreen); | |||
export default connect(mapStateToProps, mapDispatchToProps)(SignInScreen); |
@@ -1,36 +1,36 @@ | |||
import React, { Component } from "react"; | |||
import { connect } from "react-redux"; | |||
import { View, Text } from "react-native"; | |||
import React from "react"; | |||
import { ScrollView } from "react-native"; | |||
import { useDispatch } from "react-redux"; | |||
import { signOut } from "./authActions"; | |||
import Styles from "../ui/Styles"; | |||
import { Title, Button } from "react-native-paper"; | |||
import routes from "../routes"; | |||
class SignOutScreen extends Component { | |||
constructor(props) { | |||
super(props); | |||
this._signOut(); | |||
} | |||
const SignOutScreen = ({ navigation }) => { | |||
const dispatch = useDispatch(); | |||
return ( | |||
<ScrollView | |||
style={{ | |||
flex: 1, | |||
paddingTop: 20, | |||
paddingHorizontal: 10, | |||
}} | |||
> | |||
<Title style={{ marginBottom: 10 }}>Sign Out</Title> | |||
<Button | |||
compact | |||
icon="account-circle" | |||
mode="outlined" | |||
style={Styles.loginSignUpButton} | |||
onPress={() => { | |||
dispatch(signOut()); | |||
navigation.navigate(routes.PASSWORD_GENERATOR); | |||
}} | |||
> | |||
Sign out | |||
</Button> | |||
</ScrollView> | |||
); | |||
}; | |||
_signOut = async () => { | |||
const { navigation, signOut } = this.props; | |||
signOut(); | |||
navigation.navigate("Auth"); | |||
}; | |||
render() { | |||
return ( | |||
<View> | |||
<Text>Signing out</Text> | |||
</View> | |||
); | |||
} | |||
} | |||
function mapDispatchToProps(dispatch) { | |||
return { | |||
signOut: () => dispatch(signOut()) | |||
}; | |||
} | |||
export default connect( | |||
null, | |||
mapDispatchToProps | |||
)(SignOutScreen); | |||
export default SignOutScreen; |
@@ -8,6 +8,7 @@ import Styles from "../ui/Styles"; | |||
import { addError } from "../errors/errorsActions"; | |||
import { signUp } from "./authActions"; | |||
import { isEmpty } from "lodash"; | |||
import routes from "../routes"; | |||
export class SignUpScreen extends Component { | |||
constructor(props) { | |||
@@ -57,7 +58,7 @@ export class SignUpScreen extends Component { | |||
}, | |||
encryptMasterPassword | |||
) | |||
.then(() => navigation.navigate("App")) | |||
.then(() => navigation.navigate(routes.PASSWORD_GENERATOR)) | |||
.catch(error => { | |||
this.setState({ isLoading: false }); | |||
addError( | |||
@@ -74,7 +75,7 @@ export class SignUpScreen extends Component { | |||
icon="account-circle" | |||
mode="outlined" | |||
style={Styles.loginSignUpButton} | |||
onPress={() => navigation.navigate("SignIn")} | |||
onPress={() => navigation.navigate(routes.SIGN_IN)} | |||
> | |||
Sign In | |||
</Button> | |||
@@ -1,8 +1,9 @@ | |||
const initialState = { | |||
jwt: null | |||
jwt: null, | |||
isLoading: false, | |||
}; | |||
export default function(state = initialState, action) { | |||
export default function (state = initialState, action) { | |||
switch (action.type) { | |||
case "SET_JWT": | |||
return { ...state, jwt: action.jwt }; | |||
@@ -3,36 +3,38 @@ import reducer from "./authReducer"; | |||
describe("auth reducer", () => { | |||
it("should return the initial state", () => { | |||
expect(reducer(undefined, {})).toEqual({ | |||
jwt: null | |||
jwt: null, | |||
isLoading: false, | |||
}); | |||
}); | |||
it("SET_JWT", () => { | |||
expect( | |||
reducer( | |||
{ | |||
jwt: null | |||
jwt: null, | |||
}, | |||
{ | |||
type: "SET_JWT", | |||
jwt: "jwt" | |||
jwt: "jwt", | |||
} | |||
) | |||
).toEqual({ | |||
jwt: "jwt" | |||
jwt: "jwt", | |||
}); | |||
}); | |||
it("CLEAR_JWT", () => { | |||
expect( | |||
reducer( | |||
{ | |||
jwt: "jwt" | |||
jwt: "jwt", | |||
}, | |||
{ | |||
type: "CLEAR_JWT" | |||
type: "CLEAR_JWT", | |||
} | |||
) | |||
).toEqual({ | |||
jwt: null | |||
jwt: null, | |||
isLoading: false, | |||
}); | |||
}); | |||
}); |
@@ -10,17 +10,17 @@ export default class HelpScreen extends Component { | |||
style={{ | |||
flex: 1, | |||
paddingTop: 20, | |||
paddingHorizontal: 10 | |||
paddingHorizontal: 10, | |||
}} | |||
> | |||
<Title style={{ marginBottom: 10 }}>LessPass</Title> | |||
<Subheading>How does it work?</Subheading> | |||
<Paragraph style={{ marginBottom: 20 }}> | |||
LessPass is a password manager that doesn't store any data. It computes | |||
a unique password using a site, login and a master password. You don't | |||
need to sync a password vault across every device because LessPass works | |||
offline! It will always generate the same password as long as those three | |||
parameters don't change. | |||
LessPass is a password manager that doesn't store any data. It | |||
computes a unique password using a site, login and a master password. | |||
You don't need to sync a password vault across every device because | |||
LessPass works offline! It will always generate the same password as | |||
long as those three parameters don't change. | |||
</Paragraph> | |||
<Subheading>Master password emoticons</Subheading> | |||
<Image source={require("./fingerprint.png")} /> | |||
@@ -29,55 +29,54 @@ export default class HelpScreen extends Component { | |||
The emoticons on the right let you verify that you typed in the right | |||
master password. You will have to wait a second or so before the final | |||
emoticons appear (the delay is for security; if the emoticons were | |||
shown instantly, a shoulder-peeker could derive your password based | |||
on the series of displayed emoticons). | |||
shown instantly, a shoulder-peeker could derive your password based on | |||
the series of displayed emoticons). | |||
</Paragraph> | |||
<Subheading>Options</Subheading> | |||
<Image | |||
source={require("./options.png")} | |||
style={{ | |||
width: 360, | |||
height: 102 | |||
height: 102, | |||
}} | |||
/> | |||
<Paragraph style={{ marginBottom: 20 }}> | |||
Sometimes sites have specific password rules. For instance, some banks | |||
only accept passwords made of digits. LessPass lets you set parameters for | |||
the generated password (the so called "password profile"). The counter in | |||
particular allows you to generate a new password without having to change | |||
your master password. | |||
only accept passwords made of digits. LessPass lets you set parameters | |||
for the generated password (the so called "password profile"). The | |||
counter in particular allows you to generate a new password without | |||
having to change your master password. | |||
</Paragraph> | |||
<Subheading>Sign In</Subheading> | |||
<Paragraph style={{ marginBottom: 10 }}> | |||
By default, LessPass works offline and doesn't send any data over the | |||
network. For convenience, there's an optional connected mode. This mode | |||
allows you to store the profiles necessary to generate your passwords on | |||
our (or alternatively your own) LessPass server. This is especially useful | |||
if many of your passwords are not based on the default profile (length of | |||
16 characters, all characters allowed). As a password profile does neither | |||
include the master password nor the generated password, there is no | |||
critical information sent to the server. | |||
network. For convenience, there's an optional connected mode. This | |||
mode allows you to store the profiles necessary to generate your | |||
passwords on our (or alternatively your own) LessPass server. This is | |||
especially useful if many of your passwords are not based on the | |||
default profile (length of 16 characters, all characters allowed). As | |||
a password profile does neither include the master password nor the | |||
generated password, there is no critical information sent to the | |||
server. | |||
</Paragraph> | |||
<Paragraph style={{ marginBottom: 20 }}> | |||
The sign-in form asks for your master password. By default, it is used to | |||
generate a password for your LessPass account in the same way as for any other | |||
site. This means the master password itself is never sent to our servers. | |||
If for any reason you don't want to use such a LessPass-generated password | |||
for your LessPass account, you can disable this in the settings. | |||
The sign-in form asks for your master password. By default, it is used | |||
to generate a password for your LessPass account in the same way as | |||
for any other site. This means the master password itself is never | |||
sent to our servers. If for any reason you don't want to use such a | |||
LessPass-generated password for your LessPass account, you can disable | |||
this in the settings. | |||
</Paragraph> | |||
<Subheading>Self-hosted LessPass Database</Subheading> | |||
<Paragraph style={{ marginBottom: 20 }}> | |||
If you are using a self-hosted LessPass database, you can change the base | |||
url in the settings to point to your own server. | |||
</Paragraph> | |||
<Subheading>Sign Out</Subheading> | |||
<Paragraph style={{ marginBottom: 20 }}> | |||
You can sign out using the Sign Out button in the settings. | |||
If you are using a self-hosted LessPass database, you can change the | |||
base url in the settings to point to your own server. | |||
</Paragraph> | |||
<Subheading>Support</Subheading> | |||
<Paragraph> | |||
Still need some help? No problem, you can send us an email at | |||
contact@lesspass.com. You can write your email in English or French. | |||
Still need some help? Or you have an idea on how to improve LessPass. | |||
You can send us an email at contact@lesspass.com. You can write your | |||
email in English or French. | |||
</Paragraph> | |||
<Button | |||
mode="contained" | |||
@@ -87,7 +86,7 @@ export default class HelpScreen extends Component { | |||
style={{ | |||
marginTop: 10, | |||
marginBottom: 60, | |||
backgroundColor: Theme.colors.blue | |||
backgroundColor: Theme.colors.blue, | |||
}} | |||
> | |||
send us an email | |||
@@ -5,10 +5,10 @@ import { Checkbox } from "react-native-paper"; | |||
export default class Options extends Component { | |||
state = { | |||
isValid: true | |||
isValid: true, | |||
}; | |||
checkOptionsAreValid = options => { | |||
checkOptionsAreValid = (options) => { | |||
const { areOptionsValid } = this.props; | |||
if (areOptionsValid(options)) { | |||
this.setState({ isValid: true }); | |||
@@ -29,16 +29,13 @@ export default class Options extends Component { | |||
style={{ | |||
...style, | |||
flexDirection: "row", | |||
justifyContent: "space-between" | |||
justifyContent: "space-between", | |||
}} | |||
> | |||
<View | |||
style={{ | |||
flexDirection: "row", | |||
justifyContent: "center", | |||
alignItems: "center", | |||
paddingRight: 32, | |||
marginLeft: -6 | |||
}} | |||
> | |||
<Checkbox | |||
@@ -47,7 +44,7 @@ export default class Options extends Component { | |||
onPress={() => { | |||
const newOptions = { | |||
...options, | |||
lowercase: !options.lowercase | |||
lowercase: !options.lowercase, | |||
}; | |||
this.checkOptionsAreValid(newOptions); | |||
onOptionsChange(newOptions); | |||
@@ -60,7 +57,6 @@ export default class Options extends Component { | |||
flexDirection: "row", | |||
justifyContent: "center", | |||
alignItems: "center", | |||
paddingRight: 32 | |||
}} | |||
> | |||
<Checkbox | |||
@@ -69,7 +65,7 @@ export default class Options extends Component { | |||
onPress={() => { | |||
const newOptions = { | |||
...options, | |||
uppercase: !options.uppercase | |||
uppercase: !options.uppercase, | |||
}; | |||
this.checkOptionsAreValid(newOptions); | |||
onOptionsChange(newOptions); | |||
@@ -82,7 +78,6 @@ export default class Options extends Component { | |||
flexDirection: "row", | |||
justifyContent: "center", | |||
alignItems: "center", | |||
paddingRight: 32 | |||
}} | |||
> | |||
<Checkbox | |||
@@ -91,7 +86,7 @@ export default class Options extends Component { | |||
onPress={() => { | |||
const newOptions = { | |||
...options, | |||
digits: !options.digits | |||
digits: !options.digits, | |||
}; | |||
this.checkOptionsAreValid(newOptions); | |||
onOptionsChange(newOptions); | |||
@@ -102,8 +97,8 @@ export default class Options extends Component { | |||
<View | |||
style={{ | |||
flexDirection: "row", | |||
justifyContent: "center", | |||
alignItems: "center" | |||
justifyContent: "flex-end", | |||
alignItems: "center", | |||
}} | |||
> | |||
<Checkbox | |||
@@ -112,7 +107,7 @@ export default class Options extends Component { | |||
onPress={() => { | |||
const newOptions = { | |||
...options, | |||
symbols: !options.symbols | |||
symbols: !options.symbols, | |||
}; | |||
this.checkOptionsAreValid(newOptions); | |||
onOptionsChange(newOptions); | |||
@@ -37,11 +37,10 @@ export class PasswordGeneratorScreen extends Component { | |||
} | |||
componentDidMount() { | |||
const { auth, getPasswordProfiles, signOut, navigation } = this.props; | |||
const { auth, getPasswordProfiles, signOut } = this.props; | |||
if (auth.jwt) { | |||
getPasswordProfiles().catch(() => { | |||
signOut(); | |||
navigation.navigate("Auth"); | |||
}); | |||
} | |||
} | |||
@@ -0,0 +1,11 @@ | |||
const routes = { | |||
PASSWORD_GENERATOR: "LessPass", | |||
SETTINGS: "Settings", | |||
HELP: "Help", | |||
AUTH_STACK: "Sign In", | |||
SIGN_IN: "Sign In", | |||
SIGN_UP: "Sign Up", | |||
SIGN_OUT: "My account", | |||
}; | |||
export default routes; |
@@ -5,11 +5,9 @@ import { Divider, List } from "react-native-paper"; | |||
import TouchID from "react-native-touch-id"; | |||
import { setGenericPassword } from "react-native-keychain"; | |||
import { setSettings } from "./settingsActions"; | |||
import { signOut } from "../auth/authActions"; | |||
import TextInputModal from "./TextInputModal"; | |||
import Switch from "../ui/Switch"; | |||
import KeepMasterPasswordOption from "./KeepMasterPasswordOption"; | |||
import Theme from "../ui/Theme"; | |||
import { version } from "../version.json"; | |||
export class SettingsScreen extends Component { | |||
@@ -28,15 +26,9 @@ export class SettingsScreen extends Component { | |||
.catch(error => console.log(error)); | |||
} | |||
_signOut = async () => { | |||
const { navigation, signOut } = this.props; | |||
signOut(); | |||
navigation.navigate("Auth"); | |||
}; | |||
render() { | |||
const { fingerprintIsSupported } = this.state; | |||
const { auth, settings, setSettings } = this.props; | |||
const { settings, setSettings } = this.props; | |||
const { | |||
keepMasterPasswordLocally, | |||
lesspassDatabaseDefaultUrl, | |||
@@ -163,13 +155,6 @@ export class SettingsScreen extends Component { | |||
</React.Fragment> | |||
)} | |||
<List.Section title="APPLICATION"> | |||
{auth.jwt ? ( | |||
<List.Item | |||
theme={{ colors: { text: Theme.colors.red } }} | |||
title="Sign out" | |||
onPress={this._signOut} | |||
/> | |||
) : null} | |||
<List.Item title={`LessPass version: ${version}`} /> | |||
</List.Section> | |||
<Divider /> | |||
@@ -180,7 +165,6 @@ export class SettingsScreen extends Component { | |||
function mapStateToProps(state) { | |||
return { | |||
auth: state.auth, | |||
settings: state.settings | |||
}; | |||
} | |||
@@ -188,7 +172,6 @@ function mapStateToProps(state) { | |||
function mapDispatchToProps(dispatch) { | |||
return { | |||
setSettings: settings => dispatch(setSettings(settings)), | |||
signOut: () => dispatch(signOut()) | |||
}; | |||
} | |||
@@ -0,0 +1,10 @@ | |||
import React from "react"; | |||
import { ActivityIndicator, View } from "react-native"; | |||
const LoadingScreen = () => ( | |||
<View style={{ flex: 1, justifyContent: "center" }}> | |||
<ActivityIndicator size="large" color="#ffffff" /> | |||
</View> | |||
); | |||
export default LoadingScreen; |