Compare commits

..

No commits in common. "master" and "wallet-balance-extra" have entirely different histories.

117 changed files with 12830 additions and 12233 deletions

64
.gitignore vendored
View file

@ -1,66 +1,4 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/ node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/
# Other Files
android/app/google-services.json
*.log *.log
.vagrant .vagrant
android/app/build/*
android/bin

View file

@ -1,8 +0,0 @@
stages:
- build
build:
variables:
REACT_NATIVE_BRANCH: $CI_COMMIT_REF_NAME
stage: build
trigger: lbry/lbry-android

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "android"]
path = android
url = https://github.com/lbryio/lbry-android

View file

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2017-2020 LBRY Inc Copyright (c) 2017-2019 LBRY Inc
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -1,7 +1,7 @@
# LBRY React Native # LBRY Android
[![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master) [![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master)
A mobile browser and wallet for the [LBRY](https://lbry.com) network. This app bundles [LBRY SDK](https://github.com/lbryio/lbry) as a background service with a UI layer built with React Native. An Android browser and wallet for the [LBRY](https://lbry.com) network. This app bundles [lbrynet-daemon](https://github.com/lbryio/lbry) as a background service with a UI layer built with React Native. The APK is built using buildozer and the Gradle build tool.
<img src="https://spee.ch/8/lbry-android.png" alt="LBRY Android Screenshot" width="384px" /> <img src="https://spee.ch/8/lbry-android.png" alt="LBRY Android Screenshot" width="384px" />
@ -12,41 +12,10 @@ The minimum supported Android version is 5.0 Lollipop. There are two ways to ins
1. Direct APK install available at [http://build.lbry.io/android/latest.apk](http://build.lbry.io/android/latest.apk). You will need to enable installation from third-party sources on your device in order to install from this source. 1. Direct APK install available at [http://build.lbry.io/android/latest.apk](http://build.lbry.io/android/latest.apk). You will need to enable installation from third-party sources on your device in order to install from this source.
## Usage ## Usage
The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation. The app can be launched by opening **LBRY Browser** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
## Running from Source ## Running from Source
### Software Requirements The app is built from source via [Buildozer](https://github.com/kivy/buildozer). After cloning the repository, copy `buildozer.spec.sample` to `buildozer.spec` and modify this file as necessary for your environment. Please see [BUILD.md](BUILD.md) for detailed build instructions.
* Android Studio
* WebStorm (or other IDE for editing React Native / JavaScript code)
* npm
* yarn
### Android Steps
* Clone the repository using `git clone https://github.com/lbryio/lbry-react-native`
* Initialise the submodules.
```
cd lbry-react-native
git submodule update --init --recursive
```
* Install `react-native-cli` globally using `npm install -g react-native-cli`.
* Install the required package modules by running `yarn` in the cloned repository folder.
* Download a `google-services.json` from the Firebase console (https://console.firebase.google.com/) and place it in the `android/app` folder. Alternatively, use the included sample JSON file.
```
cp android/app/google-services.sample.json android/app/google-services.json
```
* Open Android Studio and click File > Open...
* Navigate to the cloned repository on your local filesystem and select the `android` subfolder.
* Connect your Android device in USB debugging mode, or create an ARM emulator (slower) to run the app.
* Click Run > Run... and select the corresponding app configuration. Note that it may take a while for the project files to sync before you can run the app
* In order to edit the React Native / JavaScript files, open the cloned repository folder using WebStorm (or your favourite IDE).
### React Native Fast Refresh
In order to enable fast refresh when updating React Native code
* Connect your Android device in USB debugging mode, or create an ARM emulator
* Run `adb reverse tcp:8081 tcp:8081` (`adb` can be found in the `platform-tools` folder of your Android SDK installation)
* Run `yarn start`
* Press `r` to reload the app.
* Anytime you make an update to the React Native code, the app should automatically refresh.
## Contributing ## Contributing
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing

View file

@ -1,14 +0,0 @@
/**
* @format
*/
import 'react-native';
import React from 'react';
import App from '../App';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
renderer.create(<App />);
});

@ -1 +0,0 @@
Subproject commit ff30e7f6a4358fd997a9e6d9f75bfe6959eafcb6

View file

@ -1,2 +0,0 @@
#!/bin/bash
react-native bundle --platform android --dev false --entry-file src/index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/

View file

@ -1,5 +1,5 @@
if (__DEV__) { if (__DEV__) {
import('./reactotron').then(() => console.log('Reactotron Configured')); import('./reactotron').then(() => console.log('Reactotron Configured'));
} }
import LBRYApp from './src/index'; import LBRYApp from './src/index';

View file

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View file

@ -1,782 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* LbryAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* LbryAppTests.m */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2DCD954D1E0B4F2C00145EB5 /* LbryAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* LbryAppTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = LbryApp;
};
2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
remoteInfo = "LbryApp-tvOS";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
00E356EE1AD99517003FC87E /* LbryAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LbryAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* LbryAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LbryAppTests.m; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* LbryApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LbryApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = LbryApp/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = LbryApp/AppDelegate.m; sourceTree = "<group>"; };
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = LbryApp/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = LbryApp/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = LbryApp/main.m; sourceTree = "<group>"; };
2D02E47B1E0B4A5D006451C7 /* LbryApp-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "LbryApp-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E4901E0B4A5D006451C7 /* LbryApp-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LbryApp-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00E356EB1AD99517003FC87E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* LbryAppTests */ = {
isa = PBXGroup;
children = (
00E356F21AD99517003FC87E /* LbryAppTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
path = LbryAppTests;
sourceTree = "<group>";
};
00E356F01AD99517003FC87E /* Supporting Files */ = {
isa = PBXGroup;
children = (
00E356F11AD99517003FC87E /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* LbryApp */ = {
isa = PBXGroup;
children = (
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */,
);
name = LbryApp;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
);
name = Libraries;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* LbryApp */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* LbryAppTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* LbryApp.app */,
00E356EE1AD99517003FC87E /* LbryAppTests.xctest */,
2D02E47B1E0B4A5D006451C7 /* LbryApp-tvOS.app */,
2D02E4901E0B4A5D006451C7 /* LbryApp-tvOSTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* LbryAppTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "LbryAppTests" */;
buildPhases = (
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
);
buildRules = (
);
dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */,
);
name = LbryAppTests;
productName = LbryAppTests;
productReference = 00E356EE1AD99517003FC87E /* LbryAppTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* LbryApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "LbryApp" */;
buildPhases = (
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
);
buildRules = (
);
dependencies = (
);
name = LbryApp;
productName = "LbryApp";
productReference = 13B07F961A680F5B00A75B9A /* LbryApp.app */;
productType = "com.apple.product-type.application";
};
2D02E47A1E0B4A5D006451C7 /* LbryApp-tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "LbryApp-tvOS" */;
buildPhases = (
FD10A7F122414F3F0027D42C /* Start Packager */,
2D02E4771E0B4A5D006451C7 /* Sources */,
2D02E4781E0B4A5D006451C7 /* Frameworks */,
2D02E4791E0B4A5D006451C7 /* Resources */,
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
);
buildRules = (
);
dependencies = (
);
name = "LbryApp-tvOS";
productName = "LbryApp-tvOS";
productReference = 2D02E47B1E0B4A5D006451C7 /* LbryApp-tvOS.app */;
productType = "com.apple.product-type.application";
};
2D02E48F1E0B4A5D006451C7 /* LbryApp-tvOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "LbryApp-tvOSTests" */;
buildPhases = (
2D02E48C1E0B4A5D006451C7 /* Sources */,
2D02E48D1E0B4A5D006451C7 /* Frameworks */,
2D02E48E1E0B4A5D006451C7 /* Resources */,
);
buildRules = (
);
dependencies = (
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
);
name = "LbryApp-tvOSTests";
productName = "LbryApp-tvOSTests";
productReference = 2D02E4901E0B4A5D006451C7 /* LbryApp-tvOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0940;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
2D02E47A1E0B4A5D006451C7 = {
CreatedOnToolsVersion = 8.2.1;
ProvisioningStyle = Automatic;
};
2D02E48F1E0B4A5D006451C7 = {
CreatedOnToolsVersion = 8.2.1;
ProvisioningStyle = Automatic;
TestTargetID = 2D02E47A1E0B4A5D006451C7;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "LbryApp" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* LbryApp */,
00E356ED1AD99517003FC87E /* LbryAppTests */,
2D02E47A1E0B4A5D006451C7 /* LbryApp-tvOS */,
2D02E48F1E0B4A5D006451C7 /* LbryApp-tvOSTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E4791E0B4A5D006451C7 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E48E1E0B4A5D006451C7 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Bundle React Native code and images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Bundle React Native Code And Images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
FD10A7F122414F3F0027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
00E356EA1AD99517003FC87E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00E356F31AD99517003FC87E /* LbryAppTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E4771E0B4A5D006451C7 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2D02E48C1E0B4A5D006451C7 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2DCD954D1E0B4F2C00145EB5 /* LbryAppTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* LbryApp */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
};
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2D02E47A1E0B4A5D006451C7 /* LbryApp-tvOS */;
targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
13B07FB21A68108700A75B9A /* Base */,
);
name = LaunchScreen.xib;
path = LbryApp;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = LbryAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LbryApp.app/LbryApp";
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = LbryAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LbryApp.app/LbryApp";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
INFOPLIST_FILE = LbryApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LbryApp;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = LbryApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = LbryApp;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
2D02E4971E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "LbryApp-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.LbryApp-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Debug;
};
2D02E4981E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "LbryApp-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.LbryApp-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Release;
};
2D02E4991E0B4A5E006451C7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "LbryApp-tvOSTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.LbryApp-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LbryApp-tvOS.app/LbryApp-tvOS";
TVOS_DEPLOYMENT_TARGET = 10.1;
};
name = Debug;
};
2D02E49A1E0B4A5E006451C7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "LbryApp-tvOSTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.LbryApp-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LbryApp-tvOS.app/LbryApp-tvOS";
TVOS_DEPLOYMENT_TARGET = 10.1;
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "LbryAppTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */,
00E356F71AD99517003FC87E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "LbryApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
13B07F951A680F5B00A75B9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "LbryApp-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2D02E4971E0B4A5E006451C7 /* Debug */,
2D02E4981E0B4A5E006451C7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "LbryApp-tvOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2D02E4991E0B4A5E006451C7 /* Debug */,
2D02E49A1E0B4A5E006451C7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "LbryApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
83CBBA211A601CBA00E9B192 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}

View file

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
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 = "LbryApp-tvOS.app"
BlueprintName = "LbryApp-tvOS"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
BuildableName = "LbryApp-tvOSTests.xctest"
BlueprintName = "LbryApp-tvOSTests"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
BuildableName = "LbryApp-tvOSTests.xctest"
BlueprintName = "LbryApp-tvOSTests"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "LbryApp-tvOS.app"
BlueprintName = "LbryApp-tvOS"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "LbryApp-tvOS.app"
BlueprintName = "LbryApp-tvOS"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "LbryApp-tvOS.app"
BlueprintName = "LbryApp-tvOS"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
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 = "LbryApp.app"
BlueprintName = "LbryApp"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "LbryAppTests.xctest"
BlueprintName = "LbryAppTests"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "LbryAppTests.xctest"
BlueprintName = "LbryAppTests"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "LbryApp.app"
BlueprintName = "LbryApp"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "LbryApp.app"
BlueprintName = "LbryApp"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "LbryApp.app"
BlueprintName = "LbryApp"
ReferencedContainer = "container:LbryApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,15 +0,0 @@
/**
* 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>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

View file

@ -1,42 +0,0 @@
/**
* 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>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"LbryApp"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end

View file

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LbryApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View file

@ -1,38 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>LbryApp</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -1,16 +0,0 @@
/**
* 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"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View file

@ -1,72 +0,0 @@
/**
* 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>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface LbryAppTests : XCTestCase
@end
@implementation LbryAppTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
{
if (test(view)) {
return YES;
}
for (UIView *subview in [view subviews]) {
if ([self findSubviewInView:subview matching:test]) {
return YES;
}
}
return NO;
}
- (void)testRendersWelcomeScreen
{
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
__block NSString *redboxError = nil;
#ifdef DEBUG
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
#endif
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
return YES;
}
return NO;
}];
}
#ifdef DEBUG
RCTSetLogFunction(RCTDefaultLogFunction);
#endif
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
}
@end

View file

@ -1,53 +0,0 @@
platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'LbryApp' do
# Pods for LbryAndroid
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/'
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
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/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
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 'LbryAndroidTests' do
inherit! :search_paths
# Pods for testing
end
use_native_modules!
end
target 'LbryAndroid-tvOS' do
# Pods for LbryAndroid-tvOS
target 'LbryAndroid-tvOSTests' do
inherit! :search_paths
# Pods for testing
end
end

View file

@ -304,23 +304,5 @@
"This content cannot be viewed at this time. Please try again in a bit.": "This content cannot be viewed at this time. Please try again in a bit.", "This content cannot be viewed at this time. Please try again in a bit.": "This content cannot be viewed at this time. Please try again in a bit.",
"Download file": "Download file", "Download file": "Download file",
"Save %title% (%size%) to your device": "Save %title% (%size%) to your device", "Save %title% (%size%) to your device": "Save %title% (%size%) to your device",
"Save \"%title%\" (%size%) to your device": "Save \"%title%\" (%size%) to your device", "Save \"%title%\" (%size%) to your device": "Save \"%title%\" (%size%) to your device"
"Find Channels to follow": "Find Channels to follow",
"LBRY works better if you follow at least 5 creators you like. Sign in to show creators you follow if you already have an account.": "LBRY works better if you follow at least 5 creators you like. Sign in to show creators you follow if you already have an account.",
"%remaining% more...": "%remaining% more...",
"Did you know that you can earn free credits worth up to %amount%?": "Did you know that you can earn free credits worth up to %amount%?",
"SHOW ME": "SHOW ME",
"Convert credits to USD on Bittrex": "Convert credits to USD on Bittrex",
"You also have": "You also have",
"in tips": "in tips",
"Earn more tips by uploading cool videos": "Earn more tips by uploading cool videos",
"You staked": "You staked",
"in your publishes": "in your publishes",
"in your supports": "in your supports",
"Your wallet is not currently synced with lbry.tv. You are responsible for backing up your wallet.": "Your wallet is not currently synced with lbry.tv. You are responsible for backing up your wallet.",
"A backup of your wallet is synced with lbry.tv": "A backup of your wallet is synced with lbry.tv",
"What does this mean?": "What does this mean?",
"LBRY credits allow you to publish or purchase content.": "LBRY credits allow you to publish or purchase content.",
"You can obtain free credits worth %amount% after you provide an email address.": "You can obtain free credits worth %amount% after you provide an email address.",
"up to": "up to"
} }

12178
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,90 +1,83 @@
{ {
"name": "LBRYApp", "name": "LBRYApp",
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": "true",
"scripts": { "scripts": {
"android": "react-native run-android", "start": "node node_modules/react-native/local-cli/cli.js start",
"ios": "react-native run-ios", "devtools": "react-devtools",
"start": "react-native start", "format": "prettier 'src/**/*.{js,json}' --write",
"test": "jest", "precommit": "lint-staged"
"lint": "eslint .", },
"format": "prettier 'src/**/*.{js,json}' --write", "dependencies": {
"precommit": "lint-staged" "base-64": "^0.1.0",
}, "@expo/vector-icons": "^8.1.0",
"dependencies": { "gfycat-style-urls": "^1.0.3",
"base-64": "^0.1.0", "lbry-redux": "lbryio/lbry-redux#acbbc66b78566da11faa0fa8c65b44a8d4302c5e",
"@expo/vector-icons": "^8.1.0", "lbryinc": "lbryio/lbryinc#138a053754ec8e3da8e9bf153d32f527c962f25c",
"gfycat-style-urls": "^1.0.3", "lodash": ">=4.17.11",
"lbry-redux": "lbryio/lbry-redux#69ffd110dbf3633e5847f61f008751edec033017", "merge": ">=1.2.1",
"lbryinc": "lbryio/lbryinc#667024ebb7cb207609273174ca422cee47469270", "moment": "^2.22.1",
"lodash": ">=4.17.11", "react": "16.9.0",
"merge": ">=1.2.1", "react-native": "0.61.5",
"moment": "^2.22.1", "@react-native-community/async-storage": "^1.5.1",
"react": "16.9.0", "@react-native-community/masked-view": "^0.1.5",
"react-native": "0.61.5", "react-native-camera": "^3.15.0",
"@react-native-community/async-storage": "^1.5.1", "react-native-country-picker-modal": "^1.10.0",
"@react-native-community/masked-view": "^0.1.5", "react-native-exception-handler": "2.10.8",
"react-native-camera": "^3.15.0", "react-native-fast-image": "^7.0.2",
"react-native-country-picker-modal": "^1.10.0", "react-native-fs": "^2.13.3",
"react-native-exception-handler": "2.10.8", "react-native-gesture-handler": "1.5.2",
"react-native-fast-image": "^7.0.2", "react-native-image-zoom-viewer": "^2.2.5",
"react-native-fs": "^2.16.6", "react-native-password-strength-meter": "^0.0.2",
"react-native-gesture-handler": "1.5.2", "react-native-phone-input": "lbryio/react-native-phone-input",
"react-native-image-zoom-viewer": "^2.2.5", "react-native-progress-circle": "2.1.0",
"react-native-password-strength-meter": "^0.0.2", "react-native-reanimated": "1.4.0",
"react-native-phone-input": "lbryio/react-native-phone-input", "react-native-safe-area-context": "^0.6.2",
"react-native-progress-circle": "2.1.0", "react-native-snackbar": "2.0.4",
"react-native-reanimated": "1.4.0", "react-native-super-grid": "^3.0.4",
"react-native-safe-area-context": "^0.6.2", "react-native-vector-icons": "^6.6.0",
"react-native-screens": "^2.0.0", "react-native-video": "lbryio/react-native-video#7992ff945872f9bd00a3736d9ff1318f343abf47",
"react-native-snackbar": "2.0.4", "react-native-webview": "^8.0.2",
"react-native-super-grid": "^3.0.4", "react-navigation": "^4.0.10",
"react-native-vector-icons": "^6.6.0", "react-navigation-drawer": "^2.3.3",
"react-native-video": "lbryio/react-native-video#7992ff945872f9bd00a3736d9ff1318f343abf47", "react-navigation-redux-helpers": "^3.0.2",
"react-native-webview": "^8.0.2", "react-navigation-tabs": "^2.7.0",
"react-navigation": "^4.0.10", "react-navigation-stack": "^1.10.3",
"react-navigation-drawer": "2.3.3", "react-redux": "^5.0.3",
"react-navigation-redux-helpers": "^3.0.2", "redux": "^4.0.4",
"react-navigation-tabs": "^2.7.0", "redux-persist": "^6.0.0",
"react-navigation-stack": "^1.10.3", "redux-persist-filesystem-storage": "^2.1.0",
"react-redux": "^5.0.3", "redux-persist-transform-compress": "^4.2.0",
"redux": "^4.0.4", "redux-persist-transform-filter": "0.0.18",
"redux-persist": "^6.0.0", "redux-thunk": "^2.3.0",
"redux-persist-filesystem-storage": "^2.1.0", "rn-fetch-blob": "0.12.0",
"redux-persist-transform-compress": "^4.2.0", "seedrandom": "3.0.3",
"redux-persist-transform-filter": "0.0.18", "showdown": "1.9.1"
"redux-thunk": "^2.3.0", },
"rn-fetch-blob": "0.12.0", "devDependencies": {
"seedrandom": "3.0.3", "@babel/core": "^7.6.2",
"showdown": "1.9.1" "babel-eslint": "10.0.2",
}, "@babel/plugin-proposal-object-rest-spread": "^7.5.4",
"devDependencies": { "babel-preset-env": "^1.6.1",
"@babel/core": "^7.6.2", "babel-preset-stage-2": "^6.18.0",
"babel-eslint": "10.0.2", "babel-plugin-module-resolver": "^3.1.1",
"@babel/plugin-proposal-object-rest-spread": "^7.5.4", "eslint": "^6.5.1",
"babel-preset-env": "^1.6.1", "eslint-config-standard": "^12.0.0",
"babel-preset-stage-2": "^6.18.0", "eslint-config-standard-jsx": "^6.0.2",
"babel-plugin-module-resolver": "^3.1.1", "eslint-plugin-flowtype": "^2.46.1",
"eslint": "^6.5.1", "eslint-plugin-import": "^2.17.2",
"eslint-config-standard": "^12.0.0", "eslint-plugin-node": "^8.0.1",
"eslint-config-standard-jsx": "^6.0.2", "eslint-plugin-promise": "^4.1.1",
"eslint-plugin-flowtype": "^2.46.1", "eslint-plugin-react": "^7.12.4",
"eslint-plugin-import": "^2.17.2", "eslint-plugin-standard": "^4.0.0",
"eslint-plugin-node": "^8.0.1", "flow-babel-webpack-plugin": "^1.1.1",
"eslint-plugin-promise": "^4.1.1", "husky": "^0.14.3",
"eslint-plugin-react": "^7.12.4", "lint-staged": "^7.0.4",
"eslint-plugin-standard": "^4.0.0", "metro-react-native-babel-preset": "^0.56.0",
"flow-babel-webpack-plugin": "^1.1.1", "prettier": "^1.11.1",
"husky": "^0.14.3", "@react-native-community/eslint-config": "^0.0.5",
"lint-staged": "^7.0.4", "react-devtools": "^3.6.3",
"metro-react-native-babel-preset": "0.56.3", "reactotron-react-native": "4.0.2",
"prettier": "^1.11.1", "reactotron-redux": "3.1.2"
"@react-native-community/eslint-config": "^0.0.5", }
"react-devtools": "^3.6.3",
"reactotron-react-native": "4.0.2",
"reactotron-redux": "3.1.2"
},
"jest": {
"preset": "react-native"
}
} }

View file

@ -5,7 +5,6 @@ import DiscoverPage from 'page/discover';
import DownloadsPage from 'page/downloads'; import DownloadsPage from 'page/downloads';
import DrawerContent from 'component/drawerContent'; import DrawerContent from 'component/drawerContent';
import FilePage from 'page/file'; import FilePage from 'page/file';
import LiteFilePage from 'page/liteFile';
import FirstRunScreen from 'page/firstRun'; import FirstRunScreen from 'page/firstRun';
import InvitesPage from 'page/invites'; import InvitesPage from 'page/invites';
import PublishPage from 'page/publish'; import PublishPage from 'page/publish';
@ -20,7 +19,7 @@ import SubscriptionsPage from 'page/subscriptions';
import TransactionHistoryPage from 'page/transactionHistory'; import TransactionHistoryPage from 'page/transactionHistory';
import VerificationScreen from 'page/verification'; import VerificationScreen from 'page/verification';
import WalletPage from 'page/wallet'; import WalletPage from 'page/wallet';
import { NavigationActions, StackActions } from 'react-navigation'; import { NavigationActions } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer'; import { createDrawerNavigator } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack'; import { createStackNavigator } from 'react-navigation-stack';
import { import {
@ -31,7 +30,6 @@ import {
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
AppState, AppState,
Alert,
BackHandler, BackHandler,
DeviceEventEmitter, DeviceEventEmitter,
Linking, Linking,
@ -42,10 +40,8 @@ import {
} from 'react-native'; } from 'react-native';
import { selectDrawerStack } from 'redux/selectors/drawer'; import { selectDrawerStack } from 'redux/selectors/drawer';
import { import {
Lbry,
ACTIONS, ACTIONS,
SETTINGS, SETTINGS,
doBalanceSubscribe,
doDismissToast, doDismissToast,
doPopulateSharedUserState, doPopulateSharedUserState,
doPreferenceGet, doPreferenceGet,
@ -54,10 +50,6 @@ import {
} from 'lbry-redux'; } from 'lbry-redux';
import { import {
Lbryio, Lbryio,
rewards as REWARD_TYPES,
doBlackListedOutpointsSubscribe,
doClaimRewardType,
doFilteredOutpointsSubscribe,
doGetSync, doGetSync,
doUserCheckEmailVerified, doUserCheckEmailVerified,
doUserEmailVerify, doUserEmailVerify,
@ -81,19 +73,27 @@ import discoverStyle from 'styles/discover';
import searchStyle from 'styles/search'; import searchStyle from 'styles/search';
import SearchRightHeaderIcon from 'component/searchRightHeaderIcon'; import SearchRightHeaderIcon from 'component/searchRightHeaderIcon';
import Snackbar from 'react-native-snackbar'; import Snackbar from 'react-native-snackbar';
import { doSetSdkReady } from 'redux/actions/settings';
const SYNC_GET_INTERVAL = 1000 * 60 * 5; // every 5 minutes const SYNC_GET_INTERVAL = 1000 * 60 * 5; // every 5 minutes
const menuNavigationButton = navigation => (
<NavigationButton
name="bars"
size={24}
style={discoverStyle.drawerMenuButton}
iconStyle={discoverStyle.drawerHamburger}
onPress={() => navigation.openDrawer()}
/>
);
const discoverStack = createStackNavigator( const discoverStack = createStackNavigator(
{ {
Subscriptions: { Discover: {
screen: SubscriptionsPage, screen: DiscoverPage,
navigationOptions: { navigationOptions: ({ navigation }) => ({
title: 'Following', title: 'Explore',
header: null, header: null,
drawerIcon: ({ tintColor }) => <Icon name="heart" solid size={drawerIconSize} style={{ color: tintColor }} />, }),
},
}, },
File: { File: {
screen: FilePage, screen: FilePage,
@ -160,17 +160,10 @@ const drawer = createDrawerNavigator(
DiscoverStack: { DiscoverStack: {
screen: discoverStack, screen: discoverStack,
navigationOptions: { navigationOptions: {
title: 'Following', title: 'Explore',
drawerIcon: ({ tintColor }) => <Icon name="home" size={drawerIconSize} style={{ color: tintColor }} />, drawerIcon: ({ tintColor }) => <Icon name="home" size={drawerIconSize} style={{ color: tintColor }} />,
}, },
}, },
Discover: {
screen: DiscoverPage,
navigationOptions: ({ navigation }) => ({
title: 'Your Tags',
header: null,
}),
},
Trending: { Trending: {
screen: TrendingPage, screen: TrendingPage,
navigationOptions: { navigationOptions: {
@ -178,6 +171,13 @@ const drawer = createDrawerNavigator(
drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />, drawerIcon: ({ tintColor }) => <Icon name="fire" size={drawerIconSize} style={{ color: tintColor }} />,
}, },
}, },
Subscriptions: {
screen: SubscriptionsPage,
navigationOptions: {
title: 'Subscriptions',
drawerIcon: ({ tintColor }) => <Icon name="heart" solid size={drawerIconSize} style={{ color: tintColor }} />,
},
},
WalletStack: { WalletStack: {
screen: walletStack, screen: walletStack,
navigationOptions: { navigationOptions: {
@ -277,12 +277,6 @@ const mainStackNavigator = new createStackNavigator(
drawerLockMode: 'locked-closed', drawerLockMode: 'locked-closed',
}, },
}, },
LiteFile: {
screen: LiteFilePage,
navigationOptions: {
drawerLockMode: 'locked-closed',
},
},
}, },
{ {
headerMode: 'none', headerMode: 'none',
@ -334,7 +328,6 @@ class AppWithNavigationState extends React.Component {
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000); this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
Linking.addEventListener('url', this._handleUrl); Linking.addEventListener('url', this._handleUrl);
DeviceEventEmitter.addListener('onSdkReady', this.handleSdkReady);
DeviceEventEmitter.addListener('onDownloadAborted', this.handleDownloadAborted); DeviceEventEmitter.addListener('onDownloadAborted', this.handleDownloadAborted);
DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted); DeviceEventEmitter.addListener('onDownloadStarted', this.handleDownloadStarted);
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated); DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
@ -374,70 +367,6 @@ class AppWithNavigationState extends React.Component {
); );
}; };
checkNewAndroidReward = () => {
const { dispatch, doToast } = this.props;
const claimRewardCallback = err => {
if (err) {
// an error occurred, do not display anything
return;
}
// reward successfully claimed
NativeModules.UtilityModule.setNativeBooleanSetting(Constants.SETTING_NEW_ANDROID_REWARD_CLAIMED, true);
};
NativeModules.UtilityModule.getNativeBooleanSetting(Constants.SETTING_NEW_ANDROID_REWARD_CLAIMED, false).then(
rewardClaimed => {
if (!rewardClaimed) {
dispatch(
doClaimRewardType(REWARD_TYPES.TYPE_NEW_ANDROID, { notifyError: false, callback: claimRewardCallback }),
);
}
},
);
};
handleSdkReady = () => {
const { dispatch } = this.props;
dispatch(doSetSdkReady());
dispatch(doBalanceSubscribe());
dispatch(doBlackListedOutpointsSubscribe());
dispatch(doFilteredOutpointsSubscribe());
Lbry.wallet_status().then(secureWalletStatus => {
// For now, automatically unlock the wallet if a password is set so that downloads work
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password => {
if ((secureWalletStatus.is_encrypted && !secureWalletStatus.is_locked) || secureWalletStatus.is_locked) {
this.setState({
message: __('Unlocking account'),
details: __('Decrypting wallet'),
});
// unlock the wallet and then finish the splash screen
Lbry.wallet_unlock({ password: password || '' }).then(unlocked => {
if (unlocked) {
} else {
// this.handleAccountUnlockFailed();
}
});
}
});
});
this.checkNewAndroidReward();
};
handleAccountUnlockFailed() {
const { dispatch } = this.props;
dispatch(
doToast({
message: __(
'Your wallet failed to unlock, which means you may not be able to play any videos or access your funds. Restart the app to fix this.',
),
isError: true,
}),
);
}
handleDownloadStarted = evt => { handleDownloadStarted = evt => {
const { dispatch } = this.props; const { dispatch } = this.props;
const { uri, outpoint, fileInfo } = evt; const { uri, outpoint, fileInfo } = evt;
@ -473,7 +402,6 @@ class AppWithNavigationState extends React.Component {
}; };
componentWillUnmount() { componentWillUnmount() {
DeviceEventEmitter.removeListener('onSdkReady', this.handleSdkReady);
DeviceEventEmitter.removeListener('onDownloadAborted', this.handleDownloadAborted); DeviceEventEmitter.removeListener('onDownloadAborted', this.handleDownloadAborted);
DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted); DeviceEventEmitter.removeListener('onDownloadStarted', this.handleDownloadStarted);
DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated); DeviceEventEmitter.removeListener('onDownloadUpdated', this.handleDownloadUpdated);

View file

@ -19,4 +19,7 @@ const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
}); });
export default connect(select, perform)(ChannelIconItem); export default connect(
select,
perform
)(ChannelIconItem);

View file

@ -19,11 +19,11 @@ const select = state => ({
const perform = dispatch => ({ const perform = dispatch => ({
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)), createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
getSync: (password, callback) => dispatch(doGetSync(password, callback)), getSync: (password, callback) => dispatch(doGetSync(password, callback)),
}); });
export default connect( export default connect(
select, select,
perform, perform
)(ChannelSelector); )(ChannelSelector);

View file

@ -23,4 +23,7 @@ const perform = dispatch => ({
claimSearch: options => dispatch(doClaimSearch(options)), claimSearch: options => dispatch(doClaimSearch(options)),
}); });
export default connect(select, perform)(ClaimList); export default connect(
select,
perform,
)(ClaimList);

View file

@ -36,4 +36,7 @@ const perform = dispatch => ({
setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)), setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)),
}); });
export default connect(select, perform)(ClaimResultItem); export default connect(
select,
perform,
)(ClaimResultItem);

View file

@ -39,14 +39,10 @@ class ClaimResultItem extends React.PureComponent {
} }
onPressHandler = () => { onPressHandler = () => {
const { autoplay, navigation, result, urlOpenHandler, setPlayerVisible } = this.props; const { autoplay, navigation, result, setPlayerVisible } = this.props;
const { claimId, name } = result; const { claimId, name } = result;
const url = normalizeURI(`${name}#${claimId}`); const url = normalizeURI(`${name}#${claimId}`);
if (urlOpenHandler) { navigateToUri(navigation, url, { autoplay }, false, url, setPlayerVisible);
urlOpenHandler(url);
} else {
navigateToUri(navigation, url, { autoplay }, false, url, setPlayerVisible);
}
}; };
render() { render() {

View file

@ -1,19 +1,18 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doToast, selectBalance, selectMyChannelClaims } from 'lbry-redux'; import { doFetchChannelListMine, selectMyChannelClaims } from 'lbry-redux';
import { selectUnclaimedRewardValue, selectUser } from 'lbryinc'; import { selectUser } from 'lbryinc';
import { selectSdkReady } from 'redux/selectors/settings';
import DrawerContent from './view'; import DrawerContent from './view';
const select = state => ({ const select = state => ({
balance: selectBalance(state),
channels: selectMyChannelClaims(state), channels: selectMyChannelClaims(state),
sdkReady: selectSdkReady(state),
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
user: selectUser(state), user: selectUser(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
notify: data => dispatch(doToast(data)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
}); });
export default connect(select, perform)(DrawerContent); export default connect(
select,
perform
)(DrawerContent);

View file

@ -6,13 +6,11 @@ import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import channelIconStyle from 'styles/channelIcon'; import channelIconStyle from 'styles/channelIcon';
import discoverStyle from 'styles/discover'; import discoverStyle from 'styles/discover';
import { Lbryio } from 'lbryinc';
import { formatUsd } from 'utils/helper';
const groupedMenuItems = { const groupedMenuItems = {
'Find content': [ 'Find content': [
{ icon: 'heart', solid: true, label: 'Following', route: Constants.DRAWER_ROUTE_SUBSCRIPTIONS },
{ icon: 'hashtag', label: 'Your Tags', route: Constants.DRAWER_ROUTE_DISCOVER }, { icon: 'hashtag', label: 'Your Tags', route: Constants.DRAWER_ROUTE_DISCOVER },
{ icon: 'heart', solid: true, label: 'Following', route: Constants.DRAWER_ROUTE_SUBSCRIPTIONS },
{ icon: 'globe-americas', label: 'All Content', route: Constants.DRAWER_ROUTE_TRENDING }, { icon: 'globe-americas', label: 'All Content', route: Constants.DRAWER_ROUTE_TRENDING },
], ],
'Your content': [ 'Your content': [
@ -33,27 +31,11 @@ const groupedMenuItems = {
}; };
const groupNames = Object.keys(groupedMenuItems); const groupNames = Object.keys(groupedMenuItems);
const routesRequiringSdkReady = [
Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
Constants.DRAWER_ROUTE_MY_LBRY,
Constants.DRAWER_ROUTE_PUBLISHES,
Constants.DRAWER_ROUTE_PUBLISH,
Constants.DRAWER_ROUTE_WALLET,
Constants.DRAWER_ROUTE_REWARDS,
Constants.DRAWER_ROUTE_INVITES,
];
class DrawerContent extends React.PureComponent { class DrawerContent extends React.PureComponent {
state = {
usdExchangeRate: 0,
};
componentDidMount() { componentDidMount() {
Lbryio.getExchangeRates().then(rates => { const { fetchChannelListMine } = this.props;
if (!isNaN(rates.LBC_USD)) { fetchChannelListMine();
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
} }
getAvatarImageUrl = () => { getAvatarImageUrl = () => {
@ -80,23 +62,8 @@ class DrawerContent extends React.PureComponent {
}); });
}; };
handleItemPress = routeName => {
const { navigation, notify, sdkReady } = this.props;
if (!sdkReady && routesRequiringSdkReady.includes(routeName)) {
if (navigation.closeDrawer) {
navigation.closeDrawer();
}
notify({
message: __('The background service is still initializing. Please try again when initialization is complete.'),
});
return;
}
navigation.navigate({ routeName: routeName });
};
render() { render() {
const { activeTintColor, balance, navigation, unclaimedRewardAmount, user, onItemPress } = this.props; const { activeTintColor, navigation, user, onItemPress } = this.props;
const { state } = navigation; const { state } = navigation;
const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null; const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null;
@ -178,7 +145,7 @@ class DrawerContent extends React.PureComponent {
const focused = const focused =
activeItemKey === item.route || activeItemKey === item.route ||
(activeItemKey === Constants.FULL_ROUTE_NAME_DISCOVER && (activeItemKey === Constants.FULL_ROUTE_NAME_DISCOVER &&
item.route === Constants.DRAWER_ROUTE_SUBSCRIPTIONS) || item.route === Constants.DRAWER_ROUTE_DISCOVER) ||
(activeItemKey === Constants.FULL_ROUTE_NAME_WALLET && (activeItemKey === Constants.FULL_ROUTE_NAME_WALLET &&
item.route === Constants.DRAWER_ROUTE_WALLET); item.route === Constants.DRAWER_ROUTE_WALLET);
return ( return (
@ -190,7 +157,7 @@ class DrawerContent extends React.PureComponent {
focused ? discoverStyle.menuItemTouchAreaFocused : null, focused ? discoverStyle.menuItemTouchAreaFocused : null,
]} ]}
key={item.label} key={item.label}
onPress={() => this.handleItemPress(item.route)} onPress={() => navigation.navigate({ routeName: item.route })}
delayPressIn={0} delayPressIn={0}
> >
<View style={discoverStyle.menuItemIcon}> <View style={discoverStyle.menuItemIcon}>
@ -203,15 +170,6 @@ class DrawerContent extends React.PureComponent {
</View> </View>
<Text style={[discoverStyle.menuItem, focused ? discoverStyle.menuItemFocused : null]}> <Text style={[discoverStyle.menuItem, focused ? discoverStyle.menuItemFocused : null]}>
{__(item.label)} {__(item.label)}
{item.label === 'Wallet' && this.state.usdExchangeRate > 0 && (
<Text> ({formatUsd(parseFloat(balance) * parseFloat(this.state.usdExchangeRate))})</Text>
)}
{item.label === 'Rewards' && this.state.usdExchangeRate > 0 && (
<Text>
{' '}
({formatUsd(parseFloat(unclaimedRewardAmount) * parseFloat(this.state.usdExchangeRate))})
</Text>
)}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
); );

View file

@ -35,4 +35,7 @@ const perform = dispatch => ({
setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)), setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)),
}); });
export default connect(select, perform)(FileItem); export default connect(
select,
perform,
)(FileItem);

View file

@ -70,9 +70,7 @@ class FileItem extends React.PureComponent {
const outpointsToHide = !blackListedOutpoints const outpointsToHide = !blackListedOutpoints
? filteredOutpoints ? filteredOutpoints
: blackListedOutpoints.concat(filteredOutpoints); : blackListedOutpoints.concat(filteredOutpoints);
shouldHide = outpointsToHide.some( shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout);
outpoint => outpoint && outpoint.txid === claim.txid && outpoint.nout === claim.nout,
);
} }
if (shouldHide) { if (shouldHide) {
// don't display blacklisted or filtered outpoints on the Your tags page // don't display blacklisted or filtered outpoints on the Your tags page

View file

@ -36,4 +36,7 @@ const perform = dispatch => ({
setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)), setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)),
}); });
export default connect(select, perform)(FileListItem); export default connect(
select,
perform,
)(FileListItem);

View file

@ -99,13 +99,9 @@ class FileListItem extends React.PureComponent {
isRewardContent, isRewardContent,
channelClaimId, channelClaimId,
fullChannelUri, fullChannelUri,
repostUrl,
repostChannel,
repostChannelUrl,
shortChannelUri, shortChannelUri,
shouldHide, shouldHide,
signingChannel, signingChannel;
isRepost;
if (claim) { if (claim) {
name = claim.name; name = claim.name;
signingChannel = claim.signing_channel; signingChannel = claim.signing_channel;
@ -115,21 +111,12 @@ class FileListItem extends React.PureComponent {
channelClaimId = signingChannel ? signingChannel.claim_id : null; channelClaimId = signingChannel ? signingChannel.claim_id : null;
fullChannelUri = channelClaimId ? `${channel}#${channelClaimId}` : channel; fullChannelUri = channelClaimId ? `${channel}#${channelClaimId}` : channel;
shortChannelUri = signingChannel ? signingChannel.short_url : null; shortChannelUri = signingChannel ? signingChannel.short_url : null;
repostUrl = claim.repost_url;
repostChannelUrl = claim.repost_channel_url;
if (repostUrl) {
const { claimName: repostName, channelName } = parseURI(repostUrl);
repostChannel = channelName;
}
isRepost = !!repostUrl;
if (blackListedOutpoints || filteredOutpoints) { if (blackListedOutpoints || filteredOutpoints) {
const outpointsToHide = !blackListedOutpoints const outpointsToHide = !blackListedOutpoints
? filteredOutpoints ? filteredOutpoints
: blackListedOutpoints.concat(filteredOutpoints); : blackListedOutpoints.concat(filteredOutpoints);
shouldHide = outpointsToHide.some( shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout);
outpoint => outpoint && outpoint.txid === claim.txid && outpoint.nout === claim.nout,
);
} }
// TODO: hide channels on tag pages? // TODO: hide channels on tag pages?
@ -140,33 +127,11 @@ class FileListItem extends React.PureComponent {
return null; return null;
} }
const actualHideChannel = !isRepost && hideChannel;
const isChannel = name && name.startsWith('@'); const isChannel = name && name.startsWith('@');
const hasThumbnail = !!thumbnail; const hasThumbnail = !!thumbnail;
return (
<View>
{isRepost && (
<View style={fileListStyle.repostInfo}>
<Icon name={'retweet'} size={14} style={fileListStyle.repostIcon} />
<Text style={fileListStyle.repostChannelName}>
<Link
text={`@${repostChannel}`}
onPress={() =>
navigateToUri(
navigation,
normalizeURI(repostChannelUrl || `@${repostChannel}`),
null,
false,
null,
false,
)
}
/>{' '}
reposted
</Text>
</View>
)}
return (
<View style={style}>
<TouchableOpacity <TouchableOpacity
style={[style, isChannel ? fileListStyle.channelContainer : null]} style={[style, isChannel ? fileListStyle.channelContainer : null]}
onPress={this.onPressHandler} onPress={this.onPressHandler}
@ -247,7 +212,7 @@ class FileListItem extends React.PureComponent {
<View style={fileListStyle.titleContainer}> <View style={fileListStyle.titleContainer}>
<Text <Text
style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title} style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}
numberOfLines={actualHideChannel ? 4 : 3} numberOfLines={hideChannel ? 4 : 3}
> >
{title || name} {title || name}
</Text> </Text>
@ -261,7 +226,7 @@ class FileListItem extends React.PureComponent {
</View> </View>
)} )}
{(channel || isChannel) && !actualHideChannel && ( {(channel || isChannel) && !hideChannel && (
<Link <Link
style={fileListStyle.publisher} style={fileListStyle.publisher}
text={isChannel ? name : channel} text={isChannel ? name : channel}

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectBalance } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'lbryinc';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants';
import FloatingWalletBalance from './view'; import FloatingWalletBalance from './view';
const select = state => ({ const select = state => ({
@ -11,4 +11,7 @@ const select = state => ({
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state), rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
}); });
export default connect(select, null)(FloatingWalletBalance); export default connect(
select,
null
)(FloatingWalletBalance);

View file

@ -36,7 +36,7 @@ class MediaPlayer extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
buffering: true, buffering: false,
backgroundPlayEnabled: false, backgroundPlayEnabled: false,
autoPaused: false, autoPaused: false,
rate: 1, rate: 1,
@ -45,9 +45,9 @@ class MediaPlayer extends React.PureComponent {
resizeMode: 'contain', resizeMode: 'contain',
duration: 0.0, duration: 0.0,
currentTime: 0.0, currentTime: 0.0,
paused: true, paused: !props.autoPlay,
fullscreenMode: false, fullscreenMode: false,
areControlsVisible: false, areControlsVisible: true,
controlsTimeout: -1, controlsTimeout: -1,
seekerOffset: 0, seekerOffset: 0,
seekerPosition: 0, seekerPosition: 0,
@ -87,9 +87,7 @@ class MediaPlayer extends React.PureComponent {
} }
onLoad = data => { onLoad = data => {
const { autoPlay } = this.props;
this.setState({ this.setState({
buffering: false,
duration: data.duration, duration: data.duration,
}); });
@ -102,17 +100,13 @@ class MediaPlayer extends React.PureComponent {
if (this.props.onMediaLoaded) { if (this.props.onMediaLoaded) {
this.props.onMediaLoaded(); this.props.onMediaLoaded();
} }
if (autoPlay) {
this.setState({ paused: false });
}
}; };
onProgress = data => { onProgress = data => {
const { savePosition, claim } = this.props; const { savePosition, claim } = this.props;
this.setState({ buffering: false, currentTime: data.currentTime }); this.setState({ buffering: false, currentTime: data.currentTime });
if (claim && data.currentTime > 0 && Math.floor(data.currentTime) % positionSaveInterval === 0) { if (data.currentTime > 0 && Math.floor(data.currentTime) % positionSaveInterval === 0) {
const { claim_id: claimId, txid, nout } = claim; const { claim_id: claimId, txid, nout } = claim;
savePosition(claimId, `${txid}:${nout}`, data.currentTime); savePosition(claimId, `${txid}:${nout}`, data.currentTime);
} }
@ -173,7 +167,7 @@ class MediaPlayer extends React.PureComponent {
togglePlay = () => { togglePlay = () => {
this.showPlayerControls(); this.showPlayerControls();
this.setState({ paused: !this.state.paused }, this.updateBackgroundMediaNotification); this.setState({ paused: !this.state.paused }, this.handlePausedState);
}; };
handlePausedState = () => { handlePausedState = () => {
@ -194,7 +188,7 @@ class MediaPlayer extends React.PureComponent {
}; };
onEnd = () => { onEnd = () => {
this.setState({ paused: true }, this.updateBackgroundMediaNotification); this.setState({ paused: true });
if (this.props.onPlaybackFinished) { if (this.props.onPlaybackFinished) {
this.props.onPlaybackFinished(); this.props.onPlaybackFinished();
} }
@ -333,10 +327,6 @@ class MediaPlayer extends React.PureComponent {
} }
}; };
onFocusChanged = evt => {
this.setState({ paused: !(this.state.paused && evt.hasAudioFocus) }, this.updateBackgroundMediaNotification);
};
onBuffer = () => { onBuffer = () => {
if (!this.state.paused) { if (!this.state.paused) {
this.setState({ buffering: true }, () => this.manualHidePlayerControls()); this.setState({ buffering: true }, () => this.manualHidePlayerControls());
@ -479,7 +469,6 @@ class MediaPlayer extends React.PureComponent {
onEnd={this.onEnd} onEnd={this.onEnd}
onError={this.onError} onError={this.onError}
minLoadRetryCount={999} minLoadRetryCount={999}
onAudioFocusChanged={this.onFocusChanged}
/> />
{this.state.firstPlay && thumbnail && ( {this.state.firstPlay && thumbnail && (

View file

@ -1,28 +0,0 @@
import { connect } from 'react-redux';
import {
doClearRepostError,
doFetchChannelListMine,
doRepost,
doToast,
selectBalance,
selectMyChannelClaims,
selectRepostError,
selectRepostLoading,
} from 'lbry-redux';
import ModalRepostView from './view';
const select = state => ({
balance: selectBalance(state),
channels: selectMyChannelClaims(state),
reposting: selectRepostLoading(state),
error: selectRepostError(state),
});
const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)),
notify: data => dispatch(doToast(data)),
repost: options => dispatch(doRepost(options)),
clearError: () => dispatch(doClearRepostError()),
});
export default connect(select, perform)(ModalRepostView);

View file

@ -1,204 +0,0 @@
import React from 'react';
import { ActivityIndicator, Alert, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { formatCredits, creditsToString } from 'lbry-redux';
import modalStyle from 'styles/modal';
import modalRepostStyle from 'styles/modalRepost';
import ChannelSelector from 'component/channelSelector';
import Button from 'component/button';
import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import { logPublish } from 'utils/helper';
export default class ModalRepostView extends React.PureComponent {
depositAmountInput;
state = {
channelName: null,
creditsInputFocused: false,
depositAmount: '0.01',
repostName: null,
repostStarted: false,
showAdvanced: false,
};
componentDidMount() {
const { claim, fetchChannelListMine } = this.props;
const { name } = claim;
fetchChannelListMine();
this.setState({ repostName: name });
this.checkChannelSelection(this.props);
}
componentWillReceiveProps(nextProps) {
this.checkChannelSelection(nextProps);
const { notify } = this.props;
const { reposting, error } = nextProps;
if (this.state.repostStarted && !reposting && error) {
this.setState({ repostStarted: false });
notify({ message: error, isError: true });
}
}
checkChannelSelection = props => {
const { channels = [] } = props;
if (!this.state.channelName && channels && channels.length > 0) {
const firstChannel = channels[0];
this.setState({ channelName: firstChannel.name });
}
};
handleChannelChange = channelName => {
const { channels = [] } = this.props;
if (channels && channels.length > 0) {
const filtered = channels.filter(c => c.name === channelName);
if (filtered.length > 0) {
const channel = filtered[0];
this.setState({ channelName });
}
}
};
handleRepost = () => {
const { claim, balance, notify, repost, onRepostSuccessful, channels = [], clearError } = this.props;
const { depositAmount, repostName, channelName } = this.state;
if (parseInt(depositAmount, 10) > balance) {
notify({
message: 'Insufficient credits',
isError: true,
});
return;
}
clearError();
const channel = channels.filter(ch => ch.name === channelName)[0];
this.setState({ repostStarted: true }, () => {
repost({
name: repostName,
bid: creditsToString(depositAmount),
channel_id: channel.claim_id,
claim_id: claim.claim_id,
}).then(repostClaim => {
logPublish(repostClaim);
this.setState({ repostStarted: false });
notify({ message: __('The content was successfully reposted!') });
if (onRepostSuccessful) onRepostSuccessful();
});
});
};
render() {
const { balance, channels, reposting, title, onCancelPress, onOverlayPress } = this.props;
const canRepost = !!this.state.channelName && !!this.state.repostName;
const channelsLoaded = channels && channels.length > 0;
const processing = this.state.repostStarted || reposting || !channelsLoaded;
return (
<TouchableOpacity style={modalStyle.overlay} activeOpacity={1} onPress={onOverlayPress}>
<TouchableOpacity style={modalStyle.container} activeOpacity={1}>
<View
style={modalRepostStyle.container}
onLayout={() => {
if (this.tipAmountInput) {
this.tipAmountInput.focus();
}
}}
>
<Text style={modalRepostStyle.title} numberOfLines={1}>
{__('Repost %title%', { title })}
</Text>
<Text style={modalRepostStyle.infoText}>
{__('Repost your favorite content to help more people discover them!')}
</Text>
<Text style={modalRepostStyle.label}>{__('Channel to post on')}</Text>
<ChannelSelector
showAnonymous={false}
channelName={this.state.channelName}
onChannelChange={this.handleChannelChange}
/>
{this.state.showAdvanced && (
<View>
<Text style={modalRepostStyle.label}>{__('Name')}</Text>
<View style={modalRepostStyle.nameRow}>
<TextInput
editable={false}
value={this.state.channelName ? `lbry://${this.state.channelName}/` : ''}
style={modalRepostStyle.input}
/>
<TextInput
editable={canRepost}
value={this.state.repostName}
underlineColorAndroid={Colors.NextLbryGreen}
selectTextOnFocus
onChangeText={value => this.setState({ repostName: value })}
style={modalRepostStyle.input}
/>
</View>
<Text style={modalRepostStyle.label}>{__('Deposit')}</Text>
<View style={modalRepostStyle.row}>
<View style={modalRepostStyle.amountRow}>
<TextInput
editable={!this.state.repostStarted}
ref={ref => (this.depositAmountInput = ref)}
onChangeText={value => this.setState({ tipAmount: value })}
underlineColorAndroid={Colors.NextLbryGreen}
keyboardType={'numeric'}
onFocus={() => this.setState({ creditsInputFocused: true })}
onBlur={() => this.setState({ creditsInputFocused: false })}
placeholder={'0'}
value={this.state.depositAmount}
selectTextOnFocus
style={modalRepostStyle.depositAmountInput}
/>
<Text style={modalRepostStyle.currency}>LBC</Text>
<View style={modalRepostStyle.balance}>
{this.state.creditsInputFocused && <Icon name="coins" size={12} />}
{this.state.creditsInputFocused && (
<Text style={modalRepostStyle.balanceText}>{formatCredits(parseFloat(balance), 1, true)}</Text>
)}
</View>
</View>
</View>
</View>
)}
<View style={modalRepostStyle.buttonRow}>
{!processing && (
<Link
style={modalRepostStyle.cancelLink}
text={__('Cancel')}
onPress={() => {
if (onCancelPress) onCancelPress();
}}
/>
)}
{processing && <ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />}
<View style={modalRepostStyle.rightButtonRow}>
<Link
style={modalRepostStyle.advancedLink}
text={this.state.showAdvanced ? __('Hide advanced') : __('Show advanced')}
onPress={() => {
this.setState({ showAdvanced: !this.state.showAdvanced });
}}
/>
<Button
text={__('Repost')}
style={modalRepostStyle.button}
disabled={!canRepost || this.state.repostStarted || reposting}
onPress={this.handleRepost}
/>
</View>
</View>
</View>
</TouchableOpacity>
</TouchableOpacity>
);
}
}

View file

@ -1,9 +1,4 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFetchingClaimSearch } from 'lbry-redux';
import ModalSuggestedSubscriptions from './view'; import ModalSuggestedSubscriptions from './view';
const select = state => ({ export default connect()(ModalSuggestedSubscriptions);
loadingSuggested: selectFetchingClaimSearch(state),
});
export default connect(select)(ModalSuggestedSubscriptions);

View file

@ -1,26 +1,23 @@
import React from 'react'; import React from 'react';
import { ActivityIndicator, ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
import modalStyle from 'styles/modal'; import modalStyle from 'styles/modal';
import subscriptionsStyle from 'styles/subscriptions'; import subscriptionsStyle from 'styles/subscriptions';
import Button from 'component/button'; import Button from 'component/button';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import SuggestedSubscriptionsGrid from 'component/suggestedSubscriptionsGrid'; import SuggestedSubscriptions from 'component/suggestedSubscriptions';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
export default class ModalSuggestedSubcriptions extends React.PureComponent { export default class ModalSuggestedSubcriptions extends React.PureComponent {
render() { render() {
const { loadingSuggested, navigation, onDonePress, onOverlayPress } = this.props; const { navigation, onDonePress, onOverlayPress } = this.props;
return ( return (
<TouchableOpacity style={modalStyle.overlay} activeOpacity={1} onPress={onOverlayPress}> <TouchableOpacity style={modalStyle.overlay} activeOpacity={1} onPress={onOverlayPress}>
<TouchableOpacity style={[modalStyle.container, subscriptionsStyle.modalContainer]} activeOpacity={1}> <TouchableOpacity style={[modalStyle.container, subscriptionsStyle.modalContainer]} activeOpacity={1}>
<SuggestedSubscriptionsGrid inModal navigation={navigation} /> <SuggestedSubscriptions inModal navigation={navigation} />
<View style={modalStyle.wideButtons}> <View style={modalStyle.buttons}>
<Button style={modalStyle.wideDoneButton} text={__('Done')} onPress={onDonePress} /> <Button style={modalStyle.doneButton} text={__('Done')} onPress={onDonePress} />
{loadingSuggested && (
<ActivityIndicator size="small" color={Colors.White} style={subscriptionsStyle.modalLoading} />
)}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
</TouchableOpacity> </TouchableOpacity>

View file

@ -1,11 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doSendTip, doToast, selectBalance } from 'lbry-redux'; import { doSendTip, doToast, selectBalance } from 'lbry-redux';
import { selectSdkReady } from 'redux/selectors/settings';
import ModalTipView from './view'; import ModalTipView from './view';
const select = state => ({ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
sdkReady: selectSdkReady(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -14,4 +12,7 @@ const perform = dispatch => ({
dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)), dispatch(doSendTip(amount, claimId, isSupport, successCallback, errorCallback)),
}); });
export default connect(select, perform)(ModalTipView); export default connect(
select,
perform
)(ModalTipView);

View file

@ -5,6 +5,7 @@ import modalStyle from 'styles/modal';
import modalTipStyle from 'styles/modalTip'; import modalTipStyle from 'styles/modalTip';
import Button from 'component/button'; import Button from 'component/button';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from 'component/link';
@ -18,22 +19,12 @@ export default class ModalTipView extends React.PureComponent {
}; };
handleSendTip = () => { handleSendTip = () => {
const { claim, balance, notify, onSendTipFailed, onSendTipSuccessful, sdkReady, sendTip } = this.props; const { claim, balance, notify, onSendTipFailed, onSendTipSuccessful, sendTip } = this.props;
const { tipAmount } = this.state; const { tipAmount } = this.state;
if (!sdkReady) {
notify({
message: __(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
),
});
return;
}
if (tipAmount > balance) { if (tipAmount > balance) {
notify({ notify({
message: 'Insufficient credits', message: 'Insufficient credits',
isError: true,
}); });
return; return;
} }
@ -65,13 +56,13 @@ export default class ModalTipView extends React.PureComponent {
() => { () => {
// error // error
if (onSendTipFailed) onSendTipFailed(); if (onSendTipFailed) onSendTipFailed();
}, }
), )
); );
}, },
}, },
], ],
{ cancelable: true }, { cancelable: true }
); );
}; };
@ -124,7 +115,7 @@ export default class ModalTipView extends React.PureComponent {
<Text style={modalTipStyle.infoText}> <Text style={modalTipStyle.infoText}>
{__( {__(
'This will appear as a tip for %content%, which will boost its ability to be discovered while active.', 'This will appear as a tip for %content%, which will boost its ability to be discovered while active.',
{ content: contentName }, { content: contentName }
)}{' '} )}{' '}
<Link <Link
style={modalTipStyle.learnMoreLink} style={modalTipStyle.learnMoreLink}

View file

@ -15,13 +15,7 @@ const RESULT_SIZE = 16;
const select = (state, props) => ({ const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
isSearching: selectIsSearching(state), isSearching: selectIsSearching(state),
recommendedContent: makeSelectResolvedRecommendedContentForUri( recommendedContent: makeSelectResolvedRecommendedContentForUri(props.uri, RESULT_SIZE)(state),
props.uri,
RESULT_SIZE,
props.claimId,
props.claimName,
props.title,
)(state),
resolvingUris: selectResolvingUris(state), resolvingUris: selectResolvingUris(state),
showNsfwContent: selectShowNsfw(state), showNsfwContent: selectShowNsfw(state),
}); });
@ -32,4 +26,7 @@ const perform = dispatch => ({
dispatch(doResolvedSearch(query, RESULT_SIZE, undefined, true, { related_to: claimId }, nsfw)), dispatch(doResolvedSearch(query, RESULT_SIZE, undefined, true, { related_to: claimId }, nsfw)),
}); });
export default connect(select, perform)(RelatedContent); export default connect(
select,
perform,
)(RelatedContent);

View file

@ -22,7 +22,7 @@ export default class RelatedContent extends React.PureComponent {
} }
render() { render() {
const { isSearching, recommendedContent, navigation, urlOpenHandler, uri, fullUri } = this.props; const { isSearching, recommendedContent, navigation, uri, fullUri } = this.props;
return ( return (
<View style={relatedContentStyle.container}> <View style={relatedContentStyle.container}>
@ -33,7 +33,6 @@ export default class RelatedContent extends React.PureComponent {
<ClaimResultItem <ClaimResultItem
style={fileListStyle.item} style={fileListStyle.item}
uri={result ? normalizeURI(`${result.name}#${result.claimId}`) : null} uri={result ? normalizeURI(`${result.name}#${result.claimId}`) : null}
urlOpenHandler={urlOpenHandler}
key={result.claimId} key={result.claimId}
result={result} result={result}
navigation={navigation} navigation={navigation}

View file

@ -1,11 +1,10 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import { formatUsd } from 'utils/helper'; import Colors from '../../styles/colors';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from '../link';
import rewardStyle from 'styles/reward'; import rewardStyle from '../../styles/reward';
type Props = { type Props = {
canClaim: boolean, canClaim: boolean,
@ -62,7 +61,7 @@ class RewardCard extends React.PureComponent<Props> {
if (reward) { if (reward) {
const claimed = !!reward.transaction_id; const claimed = !!reward.transaction_id;
if (!claimed && reward.reward_range && reward.reward_range.includes('-')) { if (!claimed && reward.reward_range && reward.reward_range.includes('-')) {
return reward.reward_range.split('-')[1]; return reward.reward_range.split('-')[0] + '+'; // ex: 5+
} else if (reward.reward_amount > 0) { } else if (reward.reward_amount > 0) {
return reward.reward_amount; return reward.reward_amount;
} }
@ -73,7 +72,7 @@ class RewardCard extends React.PureComponent<Props> {
}; };
render() { render() {
const { canClaim, isPending, onClaimPress, reward, usdExchangeRate } = this.props; const { canClaim, isPending, onClaimPress, reward } = this.props;
const claimed = !!reward.transaction_id; const claimed = !!reward.transaction_id;
return ( return (
@ -118,16 +117,8 @@ class RewardCard extends React.PureComponent<Props> {
)} )}
</View> </View>
<View style={rewardStyle.rightCol}> <View style={rewardStyle.rightCol}>
{reward.reward_range && reward.reward_range.indexOf('-') > -1 && (
<Text style={rewardStyle.rightColHeader}>{__('up to')}</Text>
)}
<Text style={rewardStyle.rewardAmount}>{this.getDisplayAmount()}</Text> <Text style={rewardStyle.rewardAmount}>{this.getDisplayAmount()}</Text>
<Text style={rewardStyle.rewardCurrency}>LBC</Text> <Text style={rewardStyle.rewardCurrency}>LBC</Text>
{usdExchangeRate > 0 && (
<Text style={rewardStyle.rewardUsd}>
&asymp;{formatUsd(parseFloat(this.getDisplayAmount()) * parseFloat(usdExchangeRate))}
</Text>
)}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
); );

View file

@ -7,7 +7,6 @@ import Link from 'component/link';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import rewardStyle from 'styles/reward'; import rewardStyle from 'styles/reward';
import { formatUsd } from '../../utils/helper';
class RewardEnrolment extends React.Component { class RewardEnrolment extends React.Component {
componentDidMount() { componentDidMount() {
@ -30,7 +29,7 @@ class RewardEnrolment extends React.Component {
}; };
render() { render() {
const { unclaimedRewardAmount, usdExchangeRate } = this.props; const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
return ( return (
<View style={rewardStyle.enrollContainer}> <View style={rewardStyle.enrollContainer}>
@ -44,11 +43,9 @@ class RewardEnrolment extends React.Component {
<View style={rewardStyle.onboarding}> <View style={rewardStyle.onboarding}>
<Text style={rewardStyle.enrollDescText}> <Text style={rewardStyle.enrollDescText}>
{__('LBRY credits allow you to publish or purchase content.')} {__('LBRY credits allow you to purchase content, publish content, and influence the network.')}
{'\n\n'} {'\n\n'}
{__('You can obtain free credits worth %amount% after you provide an email address.', { {__('You get credits for free for providing an email address and taking other basic actions.')}
amount: formatUsd(parseFloat(unclaimedRewardAmount) * parseFloat(usdExchangeRate)),
})}
{'\n\n'} {'\n\n'}
<Link style={rewardStyle.learnMoreLink} text={__('Learn more')} onPress={this.onLearnMorePressed} />. <Link style={rewardStyle.learnMoreLink} text={__('Learn more')} onPress={this.onLearnMorePressed} />.
</Text> </Text>

View file

@ -1,4 +0,0 @@
import { connect } from 'react-redux';
import SdkLoadingStatus from './view';
export default connect()(SdkLoadingStatus);

View file

@ -1,15 +0,0 @@
import { ActivityIndicator, Text, View } from 'react-native';
import React from 'react';
import discoverStyle from 'styles/discover';
import Colors from 'styles/colors';
export default class SdkLoadingStatus extends React.PureComponent {
render() {
return (
<View style={discoverStyle.sdkLoading}>
<ActivityIndicator color={Colors.White} size={'small'} />
<Text style={discoverStyle.sdkLoadingText}>{__('The LBRY background service is initializing...')}</Text>
</View>
);
}
}

View file

@ -1,18 +0,0 @@
import { connect } from 'react-redux';
import { doChannelSubscribe, doChannelUnsubscribe, selectSubscriptions, makeSelectIsSubscribed } from 'lbryinc';
import { doToast } from 'lbry-redux';
import SubscribeButtonOverlay from './view';
const select = (state, props) => ({
subscriptions: selectSubscriptions(state),
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
});
export default connect(
select,
{
doChannelSubscribe,
doChannelUnsubscribe,
doToast,
},
)(SubscribeButtonOverlay);

View file

@ -1,36 +0,0 @@
import React from 'react';
import { normalizeURI, parseURI } from 'lbry-redux';
import { NativeModules, Text, View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Button from 'component/button';
import Colors from 'styles/colors';
class SubscribeButtonOverlay extends React.PureComponent {
handlePress = () => {
const { claim, isSubscribed, doChannelSubscribe, doChannelUnsubscribe, uri } = this.props;
if (!claim) {
return;
}
const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe;
const { name: claimName } = claim;
subscriptionHandler({
channelName: claimName,
uri: normalizeURI(uri),
});
};
render() {
const { uri, isSubscribed, style } = this.props;
let styles = style.length ? style : [style];
return (
<TouchableOpacity style={styles} opacity={0.7} onPress={this.handlePress}>
{isSubscribed && <Icon name={'heart'} size={20} solid color={Colors.Red} />}
{!isSubscribed && <Icon name={'heart'} size={20} color={Colors.Red} />}
</TouchableOpacity>
);
}
}
export default SubscribeButtonOverlay;

View file

@ -6,7 +6,6 @@ import {
makeSelectTitleForUri, makeSelectTitleForUri,
makeSelectIsUriResolving, makeSelectIsUriResolving,
} from 'lbry-redux'; } from 'lbry-redux';
import { doChannelSubscribe, doChannelUnsubscribe, makeSelectIsSubscribed } from 'lbryinc';
import SuggestedSubscriptionItem from './view'; import SuggestedSubscriptionItem from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -14,13 +13,13 @@ const select = (state, props) => ({
title: makeSelectTitleForUri(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state), isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
isSubscribed: makeSelectIsSubscribed(props.uri, true)(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
subscribe: subscription => doChannelSubscribe(subscription),
unsubscribe: subscription => doChannelUnsubscribe(subscription),
}); });
export default connect(select, perform)(SuggestedSubscriptionItem); export default connect(
select,
perform
)(SuggestedSubscriptionItem);

View file

@ -1,13 +1,13 @@
import React from 'react'; import React from 'react';
import { buildURI, normalizeURI } from 'lbry-redux'; import { buildURI, normalizeURI } from 'lbry-redux';
import { ActivityIndicator, FlatList, Image, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, FlatList, Image, Text, View } from 'react-native';
import { navigateToUri } from 'utils/helper'; import { navigateToUri } from 'utils/helper';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import ChannelIconItem from 'component/channelIconItem'; import ChannelIconItem from 'component/channelIconItem';
import channelIconStyle from 'styles/channelIcon'; import channelIconStyle from 'styles/channelIcon';
import discoverStyle from 'styles/discover'; import discoverStyle from 'styles/discover';
import FileItem from 'component/fileItem'; import FileItem from 'component/fileItem';
import SubscribeButtonOverlay from 'component/subscribeButtonOverlay'; import SubscribeButton from 'component/subscribeButton';
import subscriptionsStyle from 'styles/subscriptions'; import subscriptionsStyle from 'styles/subscriptions';
import Link from 'component/link'; import Link from 'component/link';
import Tag from 'component/tag'; import Tag from 'component/tag';
@ -31,7 +31,6 @@ class SuggestedSubscriptionItem extends React.PureComponent {
render() { render() {
const { claim, isResolvingUri, navigation, thumbnail, title, uri } = this.props; const { claim, isResolvingUri, navigation, thumbnail, title, uri } = this.props;
let shortUrl, tags; let shortUrl, tags;
if (claim) { if (claim) {
shortUrl = claim.short_url; shortUrl = claim.short_url;
@ -50,7 +49,7 @@ class SuggestedSubscriptionItem extends React.PureComponent {
} }
return ( return (
<TouchableOpacity style={subscriptionsStyle.suggestedItem}> <View style={subscriptionsStyle.suggestedItem}>
<View style={[subscriptionsStyle.suggestedItemThumbnailContainer, this.state.autoStyle]}> <View style={[subscriptionsStyle.suggestedItemThumbnailContainer, this.state.autoStyle]}>
{hasThumbnail && ( {hasThumbnail && (
<Image style={subscriptionsStyle.suggestedItemThumbnail} resizeMode={'cover'} source={{ uri: thumbnail }} /> <Image style={subscriptionsStyle.suggestedItemThumbnail} resizeMode={'cover'} source={{ uri: thumbnail }} />
@ -63,37 +62,35 @@ class SuggestedSubscriptionItem extends React.PureComponent {
</View> </View>
<View style={subscriptionsStyle.suggestedItemDetails}> <View style={subscriptionsStyle.suggestedItemDetails}>
<Text style={subscriptionsStyle.suggestedItemTitle} numberOfLines={2}> {title && (
{title || claim.name} <Text style={subscriptionsStyle.suggestedItemTitle} numberOfLines={1}>
</Text> {title}
</Text>
)}
{claim && (
<Link
style={subscriptionsStyle.suggestedItemName}
numberOfLines={1}
text={claim.name}
onPress={() => navigateToUri(navigation, normalizeURI(shortUrl || uri), null, false, claim.permanent_url)}
/>
)}
{tags && ( {tags && (
<View style={subscriptionsStyle.suggestedItemTagList}> <View style={subscriptionsStyle.suggestedItemTagList}>
{tags && {tags &&
tags tags
.slice(0, 1) .slice(0, 3)
.map(tag => ( .map(tag => (
<Tag <Tag style={subscriptionsStyle.tag} key={tag} name={tag} navigation={navigation} truncate />
numberOfLines={1}
onPress={this.handleItemPress}
style={subscriptionsStyle.tag}
key={tag}
name={tag}
navigation={navigation}
truncate
/>
))} ))}
</View> </View>
)} )}
</View> </View>
{claim && ( {claim && (
<SubscribeButtonOverlay <SubscribeButton style={subscriptionsStyle.suggestedItemSubscribe} uri={normalizeURI(claim.permanent_url)} />
claim={claim}
style={subscriptionsStyle.suggestedItemSubscribeOverlay}
uri={normalizeURI(claim.permanent_url)}
/>
)} )}
</TouchableOpacity> </View>
); );
} }
} }

View file

@ -16,4 +16,7 @@ const perform = dispatch => ({
claimSearch: options => dispatch(doClaimSearch(options)), claimSearch: options => dispatch(doClaimSearch(options)),
}); });
export default connect(select, perform)(SuggestedSubscriptions); export default connect(
select,
perform
)(SuggestedSubscriptions);

View file

@ -1,27 +0,0 @@
import { connect } from 'react-redux';
import {
doClaimSearch,
selectFetchingClaimSearch,
selectClaimSearchByQuery,
selectClaimSearchByQueryLastPageReached,
selectFollowedTags,
} from 'lbry-redux';
import { selectSubscriptions, selectSuggestedChannels, selectIsFetchingSuggested } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings';
import SuggestedSubscriptionsGrid from './view';
const select = state => ({
followedTags: selectFollowedTags(state),
subscriptions: selectSubscriptions(state),
suggested: selectSuggestedChannels(state),
loading: selectIsFetchingSuggested(state) || selectFetchingClaimSearch(state),
claimSearchByQuery: selectClaimSearchByQuery(state),
lastPageReached: selectClaimSearchByQueryLastPageReached(state),
showNsfwContent: selectShowNsfw(state),
});
const perform = dispatch => ({
claimSearch: options => dispatch(doClaimSearch(options)),
});
export default connect(select, perform)(SuggestedSubscriptionsGrid);

View file

@ -1,111 +0,0 @@
import React from 'react';
import { ActivityIndicator, SectionList, Text, View } from 'react-native';
import { MATURE_TAGS, createNormalizedClaimSearchKey, normalizeURI } from 'lbry-redux';
import { navigateToUri } from 'utils/helper';
import { FlatGrid } from 'react-native-super-grid';
import SubscribeButton from 'component/subscribeButton';
import SuggestedSubscriptionItem from 'component/suggestedSubscriptionItem';
import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import discoverStyle from 'styles/discover';
import subscriptionsStyle from 'styles/subscriptions';
import Link from 'component/link';
import _ from 'lodash';
const suggestedPageSize = 24;
const softLimit = 2400;
class SuggestedSubscriptionsGrid extends React.PureComponent {
state = {
currentPage: 1,
options: {},
// maintain a local state of subscriptions so that changes don't affect the search
subscriptionIds: [],
};
buildClaimSearchOptions() {
const { showNsfwContent } = this.props;
const { currentPage } = this.state;
const options = {
no_totals: true,
page: currentPage,
page_size: suggestedPageSize,
claim_type: 'channel',
order_by: [Constants.ORDER_BY_EFFECTIVE_AMOUNT],
};
if (!showNsfwContent) {
options.not_tags = MATURE_TAGS;
}
if (this.state.subscriptionIds.length > 0) {
options.not_channel_ids = this.state.subscriptionIds;
}
return options;
}
doClaimSearch() {
const { claimSearch } = this.props;
const options = this.buildClaimSearchOptions();
claimSearch(options);
}
handleVerticalEndReached = () => {
// fetch more content
const { claimSearchByQuery, lastPageReached } = this.props;
const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options);
const uris = claimSearchByQuery[claimSearchKey];
if (
lastPageReached[claimSearchKey] ||
(uris.length > 0 && uris.length < suggestedPageSize) || uris.length >= softLimit
) {
return;
}
this.setState({ currentPage: this.state.currentPage + 1 }, () => this.doClaimSearch());
};
componentDidMount() {
const { claimSearch, followedTags, showNsfwContent, subscriptions } = this.props;
if (subscriptions && subscriptions.length > 0) {
this.setState(
{
subscriptionIds: subscriptions.map(subscription => subscription.uri.split('#')[1]),
},
() => this.doClaimSearch(),
);
} else {
this.doClaimSearch();
}
}
render() {
const { claimSearchByQuery, inModal, navigation } = this.props;
const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options);
const claimSearchUris = claimSearchByQuery[claimSearchKey];
return (
<FlatGrid
initialNumToRender={24}
maxToRenderPerBatch={48}
removeClippedSubviews
itemDimension={120}
spacing={1}
items={claimSearchUris}
style={inModal ? subscriptionsStyle.modalScrollContainer : subscriptionsStyle.scrollContainer}
contentContainerStyle={
inModal ? subscriptionsStyle.modalSuggestedScrollContent : subscriptionsStyle.suggestedScrollContent
}
renderItem={({ item, index }) => (
<SuggestedSubscriptionItem key={item} uri={normalizeURI(item)} navigation={navigation} />
)}
onEndReached={this.handleVerticalEndReached}
onEndReachedThreshold={0.2}
/>
);
}
}
export default SuggestedSubscriptionsGrid;

View file

@ -30,7 +30,7 @@ export default class Tag extends React.PureComponent {
}; };
render() { render() {
const { name, numberOfLines, onPress, style, type, truncate } = this.props; const { name, onPress, style, type, truncate } = this.props;
let styles = []; let styles = [];
if (style) { if (style) {
@ -50,9 +50,7 @@ export default class Tag extends React.PureComponent {
return ( return (
<TouchableOpacity style={styles} onPress={onPress || this.onPressDefault}> <TouchableOpacity style={styles} onPress={onPress || this.onPressDefault}>
<View style={tagStyle.content}> <View style={tagStyle.content}>
<Text style={tagStyle.text} numberOfLines={numberOfLines}> <Text style={tagStyle.text}>{truncate ? formatTagName(name) : name}</Text>
{truncate ? formatTagName(name) : name}
</Text>
{type && <Icon style={tagStyle.icon} name={type === 'add' ? 'plus' : 'times'} size={8} />} {type && <Icon style={tagStyle.icon} name={type === 'add' ? 'plus' : 'times'} size={8} />}
</View> </View>
</TouchableOpacity> </TouchableOpacity>

View file

@ -1,14 +1,13 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux'; import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux';
import { Alert, Dimensions, FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { Dimensions, FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { navigateToUri, transformUrl } from 'utils/helper'; import { navigateToUri, transformUrl } from 'utils/helper';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import UriBarItem from './internal/uri-bar-item'; import UriBarItem from './internal/uri-bar-item';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import NavigationButton from 'component/navigationButton'; import NavigationButton from 'component/navigationButton';
import uriBarStyle from 'styles/uriBar'; import uriBarStyle from 'styles/uriBar';
import { NavigationActions, StackActions } from 'react-navigation';
class UriBar extends React.PureComponent { class UriBar extends React.PureComponent {
static INPUT_TIMEOUT = 2500; // 2.5 seconds static INPUT_TIMEOUT = 2500; // 2.5 seconds
@ -184,33 +183,6 @@ class UriBar extends React.PureComponent {
}); });
}; };
handleNavigationButtonPress = () => {
const { navigation } = this.props;
if (!navigation.openDrawer) {
Alert.alert(
__('Stop watching?'),
'The LBRY service is still loading stuff in the background. Would you like to continue?',
[
{ text: __('No') },
{
text: __('Yes'),
onPress: () => {
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Splash', params: { resetUrl: 'lbry://?subscriptions' } }),
],
});
navigation.dispatch(resetAction);
},
},
],
);
} else {
navigation.openDrawer();
}
};
render() { render() {
const { const {
allowEdit, allowEdit,
@ -290,7 +262,7 @@ class UriBar extends React.PureComponent {
size={24} size={24}
style={uriBarStyle.drawerMenuButton} style={uriBarStyle.drawerMenuButton}
iconStyle={uriBarStyle.drawerHamburger} iconStyle={uriBarStyle.drawerHamburger}
onPress={this.handleNavigationButtonPress} onPress={() => navigation.openDrawer()}
/> />
)} )}
{!selectionMode && ( {!selectionMode && (

View file

@ -6,4 +6,7 @@ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
}); });
export default connect(select, null)(WalletBalance); export default connect(
select,
null
)(WalletBalance);

View file

@ -1,9 +1,9 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { Image, Text, View } from 'react-native'; import { Image, Text, View } from 'react-native';
import { formatCredits } from 'lbry-redux'; import { Lbry, formatCredits } from 'lbry-redux';
import { Lbryio } from 'lbryinc'; import Address from 'component/address';
import { formatUsd } from 'utils/helper'; import Button from 'component/button';
import walletStyle from 'styles/wallet'; import walletStyle from 'styles/wallet';
type Props = { type Props = {
@ -11,18 +11,6 @@ type Props = {
}; };
class WalletBalance extends React.PureComponent<Props> { class WalletBalance extends React.PureComponent<Props> {
state = {
usdExchangeRate: 0,
};
componentDidMount() {
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
}
render() { render() {
const { balance } = this.props; const { balance } = this.props;
return ( return (
@ -33,13 +21,6 @@ class WalletBalance extends React.PureComponent<Props> {
<Text style={walletStyle.balance}> <Text style={walletStyle.balance}>
{(balance || balance === 0) && formatCredits(parseFloat(balance), 2) + ' LBC'} {(balance || balance === 0) && formatCredits(parseFloat(balance), 2) + ' LBC'}
</Text> </Text>
<Text style={walletStyle.usdBalance}>
{this.state.usdExchangeRate > 0 && (
<Text>
&asymp;{formatUsd(isNaN(balance) ? 0 : parseFloat(balance) * parseFloat(this.state.usdExchangeRate))}
</Text>
)}
</Text>
</View> </View>
); );
} }

View file

@ -1,14 +1,14 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimsBalance, selectSupportsBalance, selectTipsBalance } from 'lbry-redux'; import { selectClaimsBalance, selectSupportsBalance, selectTipsBalance } from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import WalletBalanceExtra from './view'; import WalletBalanceExtra from './view';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
const select = state => ({ const select = state => ({
claimsBalance: selectClaimsBalance(state) || 0, claimsBalance: selectClaimsBalance(state) || 0,
deviceWalletSynced: makeSelectClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED)(state),
supportsBalance: selectSupportsBalance(state) || 0, supportsBalance: selectSupportsBalance(state) || 0,
tipsBalance: selectTipsBalance(state) || 0, tipsBalance: selectTipsBalance(state) || 0,
}); });
export default connect(select, null)(WalletBalanceExtra); export default connect(
select,
null,
)(WalletBalanceExtra);

View file

@ -1,14 +1,12 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { Text, View } from 'react-native'; import { Image, Text, View } from 'react-native';
import { formatCredits } from 'lbry-redux'; import { Lbry, formatCredits } from 'lbry-redux';
import { Lbryio } from 'lbryinc'; import Address from 'component/address';
import { formatUsd } from 'utils/helper'; import Button from 'component/button';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import walletStyle from 'styles/wallet'; import walletStyle from 'styles/wallet';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
type Props = { type Props = {
claimsBalance: number, claimsBalance: number,
@ -17,95 +15,36 @@ type Props = {
}; };
class WalletBalanceExtra extends React.PureComponent<Props> { class WalletBalanceExtra extends React.PureComponent<Props> {
state = {
usdExchangeRate: 0,
};
componentDidMount() {
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
}
render() { render() {
const { claimsBalance, deviceWalletSynced, navigation, supportsBalance, tipsBalance } = this.props; const { claimsBalance, supportsBalance, tipsBalance } = this.props;
return ( return (
<View style={walletStyle.balanceExtra}> <View style={walletStyle.balanceExtraCard}>
<View style={walletStyle.usdInfoCard}> <View style={walletStyle.walletExtraRow}>
<Text style={walletStyle.usdInfoText}> <View style={walletStyle.walletExtraCol}>
You can convert your credits to USD and withdraw the converted amount using an exchange.{' '} <Icon style={walletStyle.walletExtraIcon} color={Colors.LbryGreen} name={'gift'} size={16} />
<Link <Text style={walletStyle.walletExtraCaption}>{__('You also have')}</Text>
style={walletStyle.usdConvertFaqLink} <View style={walletStyle.balanceRow}>
href={'https://lbry.com/faq/exchanges'} <Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(tipsBalance), 2)}</Text>
text={__('Learn more')} <Text style={walletStyle.walletExtraCurrency}>LBC</Text>
/>
.
</Text>
<Link
style={walletStyle.usdConvertLink}
href={'https://bittrex.com/Account/Register?referralCode=4M1-P30-BON'}
text={__('Convert credits to USD on Bittrex')}
/>
</View>
<View style={walletStyle.balanceExtraCard}>
<View style={walletStyle.walletExtraRow}>
<View style={walletStyle.walletExtraCol}>
<Icon style={walletStyle.walletExtraIcon} color={Colors.LbryGreen} name={'gift'} size={16} />
<Text style={walletStyle.walletExtraCaption}>{__('You also have')}</Text>
<View style={walletStyle.balanceRow}>
<Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(tipsBalance), 2)}</Text>
<Text style={walletStyle.walletExtraCurrency}>LBC</Text>
</View>
<Text style={walletStyle.usdWalletExtraBalance}>
&asymp;{formatUsd(parseFloat(tipsBalance) * parseFloat(this.state.usdExchangeRate))}
</Text>
<Text style={walletStyle.text}>{__('in tips')}</Text>
<Link
style={walletStyle.earnTipsLink}
onPress={() => {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH });
}}
text={__('Earn more tips by uploading cool videos')}
/>
</View>
<View style={walletStyle.walletExtraCol}>
<Icon style={walletStyle.walletExtraIcon} color={Colors.LbryGreen} name={'lock'} size={16} />
<Text style={walletStyle.walletExtraCaption}>{__('You staked')}</Text>
<View style={walletStyle.balanceRow}>
<Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(claimsBalance), 2)}</Text>
<Text style={walletStyle.walletExtraCurrency}>LBC</Text>
</View>
<Text style={walletStyle.text}>{__('in your publishes')}</Text>
<View style={[walletStyle.balanceRow, walletStyle.walletExtraTopMargin]}>
<Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(supportsBalance), 2)}</Text>
<Text style={walletStyle.walletExtraCurrency}>LBC</Text>
</View>
<Text style={walletStyle.text}>{__('in your supports')}</Text>
</View> </View>
<Text style={walletStyle.text}>{__('in tips')}</Text>
</View> </View>
</View>
<View style={walletStyle.syncDriverCustody}> <View style={walletStyle.walletExtraCol}>
<Text style={walletStyle.syncInfoText}> <Icon style={walletStyle.walletExtraIcon} color={Colors.LbryGreen} name={'lock'} size={16} />
{deviceWalletSynced <Text style={walletStyle.walletExtraCaption}>{__('You staked')}</Text>
? __('A backup of your wallet is synced with lbry.tv') <View style={walletStyle.balanceRow}>
: __('Your wallet is not currently synced with lbry.tv. You are responsible for backing up your wallet.')} <Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(claimsBalance), 2)}</Text>
</Text> <Text style={walletStyle.walletExtraCurrency}>LBC</Text>
<Link </View>
text={__('What does this mean?')} <Text style={walletStyle.text}>{__('in your publishes')}</Text>
href={ <View style={[walletStyle.balanceRow, walletStyle.walletExtraTopMargin]}>
deviceWalletSynced <Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(supportsBalance), 2)}</Text>
? 'https://lbry.com/faq/account-sync' <Text style={walletStyle.walletExtraCurrency}>LBC</Text>
: 'https://lbry.com/faq/how-to-backup-wallet#android' </View>
} <Text style={walletStyle.text}>{__('in your supports')}</Text>
style={walletStyle.syncInfoLink} </View>
/>
</View> </View>
</View> </View>
); );

View file

@ -27,7 +27,7 @@ class WalletSyncDriver extends React.PureComponent<Props> {
}, },
}, },
], ],
{ cancelable: true }, { cancelable: true }
); );
} }
}; };

View file

@ -44,10 +44,6 @@ const Constants = {
SETTING_BACKUP_DISMISSED: 'backupDismissed', SETTING_BACKUP_DISMISSED: 'backupDismissed',
SETTING_REWARDS_NOT_INTERESTED: 'rewardsNotInterested', SETTING_REWARDS_NOT_INTERESTED: 'rewardsNotInterested',
SETTING_DEVICE_WALLET_SYNCED: 'deviceWalletSynced', SETTING_DEVICE_WALLET_SYNCED: 'deviceWalletSynced',
SETTING_DHT_ENABLED: 'dhtEnabled',
SETTING_NEW_ANDROID_REWARD_CLAIMED: 'newAndroidRewardClaimed',
ACTION_SDK_READY: 'SDK_READY',
ACTION_DELETE_COMPLETED_BLOBS: 'DELETE_COMPLETED_BLOBS', ACTION_DELETE_COMPLETED_BLOBS: 'DELETE_COMPLETED_BLOBS',
ACTION_FIRST_RUN_PAGE_CHANGED: 'FIRST_RUN_PAGE_CHANGED', ACTION_FIRST_RUN_PAGE_CHANGED: 'FIRST_RUN_PAGE_CHANGED',
@ -68,8 +64,6 @@ const Constants = {
ACTION_CLEAR_PUBLISH_FORM_STATE: 'CLEAR_PUBLISH_FORM_STATE', ACTION_CLEAR_PUBLISH_FORM_STATE: 'CLEAR_PUBLISH_FORM_STATE',
ACTION_CLEAR_CHANNEL_FORM_STATE: 'CLEAR_CHANNEL_FORM_STATE', ACTION_CLEAR_CHANNEL_FORM_STATE: 'CLEAR_CHANNEL_FORM_STATE',
ACTION_SET_EXPLICIT_NAVIGATE_BACK: 'SET_EXPLICIT_NAVIGATE_BACK',
ACTION_FULLSCREEN_MODE_TOGGLED: 'FULLSCREEN_MODE_TOGGLED', ACTION_FULLSCREEN_MODE_TOGGLED: 'FULLSCREEN_MODE_TOGGLED',
ORIENTATION_HORIZONTAL: 'horizontal', ORIENTATION_HORIZONTAL: 'horizontal',
@ -97,7 +91,6 @@ const Constants = {
DRAWER_ROUTE_CHANNEL_CREATOR: 'ChannelCreator', DRAWER_ROUTE_CHANNEL_CREATOR: 'ChannelCreator',
DRAWER_ROUTE_CHANNEL_CREATOR_FORM: 'ChannnelCreatorForm', DRAWER_ROUTE_CHANNEL_CREATOR_FORM: 'ChannnelCreatorForm',
DRAWER_ROUTE_INVITES: 'Invites', DRAWER_ROUTE_INVITES: 'Invites',
DRAWER_ROUTE_LITE_FILE: 'LiteFile',
FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack', FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack',
FULL_ROUTE_NAME_WALLET: 'WalletStack', FULL_ROUTE_NAME_WALLET: 'WalletStack',
@ -150,7 +143,7 @@ const Constants = {
TRUE_STRING: 'true', TRUE_STRING: 'true',
MINIMUM_TRANSACTION_BALANCE: 0.01, MINIMUM_TRANSACTION_BALANCE: 0.1,
SHARE_BASE_URL: 'https://open.lbry.com', SHARE_BASE_URL: 'https://open.lbry.com',
}; };

View file

@ -55,10 +55,6 @@ import settingsReducer from 'redux/reducers/settings';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
window.__ = __; window.__ = __;
if (!NativeModules.UtilityModule.dhtEnabled) {
Lbry.alternateConnectionString = 'https://api.lbry.tv/api/v1/proxy';
Lbry.methodsUsingAlternateConnectionString = ['claim_search', 'resolve'];
}
const globalExceptionHandler = (error, isFatal) => { const globalExceptionHandler = (error, isFatal) => {
if (error && NativeModules.Firebase) { if (error && NativeModules.Firebase) {

View file

@ -10,7 +10,6 @@ import aboutStyle from 'styles/about';
class AboutPage extends React.PureComponent { class AboutPage extends React.PureComponent {
state = { state = {
appVersion: null, appVersion: null,
firebaseToken: null,
lbryId: null, lbryId: null,
versionInfo: null, versionInfo: null,
}; };
@ -46,12 +45,11 @@ class AboutPage extends React.PureComponent {
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('About').then(result => { NativeModules.Firebase.setCurrentScreen('About').then(result => {
NativeModules.VersionInfo.getAppVersion().then(version => { if (NativeModules.VersionInfo) {
this.setState({ appVersion: version }); NativeModules.VersionInfo.getAppVersion().then(version => {
}); this.setState({ appVersion: version });
NativeModules.Firebase.getMessagingToken().then(firebaseToken => { });
this.setState({ firebaseToken }); }
});
Lbry.version().then(info => { Lbry.version().then(info => {
this.setState({ this.setState({
versionInfo: info, versionInfo: info,
@ -79,7 +77,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.title}>{__('Content Freedom')}</Text> <Text style={aboutStyle.title}>{__('Content Freedom')}</Text>
<Text style={aboutStyle.paragraph}> <Text style={aboutStyle.paragraph}>
{__( {__(
'LBRY is a free, open, and community-run digital marketplace. It is a decentralized peer-to-peer content distribution platform for creators to upload and share content, and earn LBRY credits for their effort. Users will be able to find a wide selection of videos, music, ebooks and other digital content they are interested in.', 'LBRY is a free, open, and community-run digital marketplace. It is a decentralized peer-to-peer content distribution platform for creators to upload and share content, and earn LBRY credits for their effort. Users will be able to find a wide selection of videos, music, ebooks and other digital content they are interested in.'
)} )}
</Text> </Text>
<View style={aboutStyle.links}> <View style={aboutStyle.links}>
@ -90,7 +88,7 @@ class AboutPage extends React.PureComponent {
<Text style={aboutStyle.socialTitle}>{__('Get Social')}</Text> <Text style={aboutStyle.socialTitle}>{__('Get Social')}</Text>
<Text style={aboutStyle.paragraph}> <Text style={aboutStyle.paragraph}>
{__( {__(
'You can interact with the LBRY team and members of the community on Discord, Facebook, Instagram, Twitter or Reddit.', 'You can interact with the LBRY team and members of the community on Discord, Facebook, Instagram, Twitter or Reddit.'
)} )}
</Text> </Text>
<View style={aboutStyle.links}> <View style={aboutStyle.links}>
@ -166,15 +164,6 @@ class AboutPage extends React.PureComponent {
</View> </View>
</View> </View>
<View style={aboutStyle.row}>
<View style={aboutStyle.col}>
<Text style={aboutStyle.text}>{__('Firebase Token')}</Text>
<Text selectable style={aboutStyle.lineValueText}>
{this.state.firebaseToken ? this.state.firebaseToken : loading}
</Text>
</View>
</View>
<View style={aboutStyle.row}> <View style={aboutStyle.row}>
<View style={aboutStyle.col}> <View style={aboutStyle.col}>
<Text style={aboutStyle.text}>{__('Logs')}</Text> <Text style={aboutStyle.text}>{__('Logs')}</Text>

View file

@ -18,7 +18,7 @@ const select = (state, props) => ({
const perform = dispatch => ({ const perform = dispatch => ({
abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)), abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
fetchSubCount: claimId => dispatch(doFetchSubCount(claimId)), fetchSubCount: claimId => dispatch(doFetchSubCount(claimId)),
popDrawerStack: () => dispatch(doPopDrawerStack()), popDrawerStack: () => dispatch(doPopDrawerStack()),
setSortByItem: item => dispatch(doSetSortByItem(item)), setSortByItem: item => dispatch(doSetSortByItem(item)),
@ -27,5 +27,5 @@ const perform = dispatch => ({
export default connect( export default connect(
select, select,
perform, perform
)(ChannelPage); )(ChannelPage);

View file

@ -173,10 +173,9 @@ class ChannelPage extends React.PureComponent {
const { permanent_url: permanentUrl } = claim; const { permanent_url: permanentUrl } = claim;
navigation.navigate({ navigation.navigate({
routeName: Constants.DRAWER_ROUTE_CHANNEL_CREATOR, routeName: Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
params: { editChannelUrl: permanentUrl, returnUrl: permanentUrl }, params: { editChannelUrl: permanentUrl },
}); });
} }
this.onEditPressed = null;
}; };
onTipPressed = () => { onTipPressed = () => {
@ -211,7 +210,7 @@ class ChannelPage extends React.PureComponent {
}, },
}, },
], ],
{ cancelable: true }, { cancelable: true }
); );
} }
}; };

View file

@ -13,16 +13,10 @@ import {
doToast, doToast,
} from 'lbry-redux'; } from 'lbry-redux';
import { doGetSync } from 'lbryinc'; import { doGetSync } from 'lbryinc';
import { import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
doPushDrawerStack,
doPopDrawerStack,
doSetPlayerVisible,
doSetExplicitNavigateBack,
} from 'redux/actions/drawer';
import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form'; import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form';
import { selectDrawerStack } from 'redux/selectors/drawer'; import { selectDrawerStack } from 'redux/selectors/drawer';
import { selectChannelFormState, selectHasChannelFormState } from 'redux/selectors/form'; import { selectChannelFormState, selectHasChannelFormState } from 'redux/selectors/form';
import { selectSdkReady } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import ChannelCreator from './view'; import ChannelCreator from './view';
@ -34,7 +28,6 @@ const select = state => ({
fetchingChannels: selectFetchingMyChannels(state), fetchingChannels: selectFetchingMyChannels(state),
balance: selectBalance(state), balance: selectBalance(state),
hasFormState: selectHasChannelFormState(state), hasFormState: selectHasChannelFormState(state),
sdkReady: selectSdkReady(state),
updatingChannel: selectUpdatingChannel(state), updatingChannel: selectUpdatingChannel(state),
updateChannelError: selectUpdateChannelError(state), updateChannelError: selectUpdateChannelError(state),
}); });
@ -44,14 +37,16 @@ const perform = dispatch => ({
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
clearChannelFormState: () => dispatch(doClearChannelFormState()), clearChannelFormState: () => dispatch(doClearChannelFormState()),
createChannel: (name, amount, optionalParams) => dispatch(doCreateChannel(name, amount, optionalParams)), createChannel: (name, amount, optionalParams) => dispatch(doCreateChannel(name, amount, optionalParams)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
getSync: (password, callback) => dispatch(doGetSync(password, callback)), getSync: (password, callback) => dispatch(doGetSync(password, callback)),
updateChannel: params => dispatch(doUpdateChannel(params)), updateChannel: params => dispatch(doUpdateChannel(params)),
updateChannelFormState: data => dispatch(doUpdateChannelFormState(data)), updateChannelFormState: data => dispatch(doUpdateChannelFormState(data)),
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)), pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
popDrawerStack: () => dispatch(doPopDrawerStack()), popDrawerStack: () => dispatch(doPopDrawerStack()),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setExplicitNavigateBack: flag => dispatch(doSetExplicitNavigateBack(flag)),
}); });
export default connect(select, perform)(ChannelCreator); export default connect(
select,
perform
)(ChannelCreator);

View file

@ -14,7 +14,7 @@ import {
TouchableOpacity, TouchableOpacity,
View, View,
} from 'react-native'; } from 'react-native';
import { navigateBack, navigateToUri, logPublish, uploadImageAsset } from 'utils/helper'; import { navigateToUri, logPublish, uploadImageAsset } from 'utils/helper';
import Button from 'component/button'; import Button from 'component/button';
import ChannelIconItem from 'component/channelIconItem'; import ChannelIconItem from 'component/channelIconItem';
import ChannelRewardsDriver from 'component/channelRewardsDriver'; import ChannelRewardsDriver from 'component/channelRewardsDriver';
@ -37,7 +37,6 @@ export default class ChannelCreator extends React.PureComponent {
state = { state = {
autoStyle: null, autoStyle: null,
returnUrl: null,
canSave: true, canSave: true,
claimId: null, claimId: null,
creditsInputFocused: false, creditsInputFocused: false,
@ -47,7 +46,7 @@ export default class ChannelCreator extends React.PureComponent {
channelNameUserEdited: false, channelNameUserEdited: false,
newChannelTitle: '', newChannelTitle: '',
newChannelName: '', newChannelName: '',
newChannelBid: 0.01, newChannelBid: 0.1,
addingChannel: false, addingChannel: false,
creatingChannel: false, creatingChannel: false,
editChannelUrl: null, editChannelUrl: null,
@ -78,7 +77,6 @@ export default class ChannelCreator extends React.PureComponent {
descriptionFocused: false, descriptionFocused: false,
websiteFocused: false, websiteFocused: false,
emailFocused: false, emailFocused: false,
hasReturnedBack: false,
}; };
didFocusListener; didFocusListener;
@ -120,14 +118,7 @@ export default class ChannelCreator extends React.PureComponent {
}; };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { const { currentRoute: prevRoute, drawerStack: prevDrawerStack, notify } = this.props;
currentRoute: prevRoute,
drawerStack: prevDrawerStack,
popDrawerStack,
setPlayerVisible,
navigation,
notify,
} = this.props;
const { currentRoute, drawerStack, updatingChannel, updateChannelError } = nextProps; const { currentRoute, drawerStack, updatingChannel, updateChannelError } = nextProps;
if (Constants.DRAWER_ROUTE_CHANNEL_CREATOR === currentRoute && currentRoute !== prevRoute) { if (Constants.DRAWER_ROUTE_CHANNEL_CREATOR === currentRoute && currentRoute !== prevRoute) {
@ -151,11 +142,6 @@ export default class ChannelCreator extends React.PureComponent {
) { ) {
// navigated back from the form // navigated back from the form
this.setState({ currentPhase: Constants.PHASE_LIST }); this.setState({ currentPhase: Constants.PHASE_LIST });
if (!this.state.hasReturnedBack && this.state.returnUrl) {
this.setState({ hasReturnedBack: true }, () => {
navigateBack(navigation, drawerStack, popDrawerStack, setPlayerVisible);
});
}
} }
} }
@ -176,19 +162,20 @@ export default class ChannelCreator extends React.PureComponent {
NativeModules.Firebase.setCurrentScreen('Channels').then(result => { NativeModules.Firebase.setCurrentScreen('Channels').then(result => {
pushDrawerStack(Constants.DRAWER_ROUTE_CHANNEL_CREATOR, navigation.state.params ? navigation.state.params : null); pushDrawerStack(Constants.DRAWER_ROUTE_CHANNEL_CREATOR, navigation.state.params ? navigation.state.params : null);
setPlayerVisible(); setPlayerVisible();
fetchChannelListMine(); if (!fetchingChannels) {
fetchChannelListMine();
}
DeviceEventEmitter.addListener('onDocumentPickerFilePicked', this.onFilePicked); DeviceEventEmitter.addListener('onDocumentPickerFilePicked', this.onFilePicked);
DeviceEventEmitter.addListener('onDocumentPickerCanceled', this.onPickerCanceled); DeviceEventEmitter.addListener('onDocumentPickerCanceled', this.onPickerCanceled);
let isEditMode = false; let isEditMode = false;
if (navigation.state.params) { if (navigation.state.params) {
const { editChannelUrl, displayForm, returnUrl } = navigation.state.params; const { editChannelUrl, displayForm } = navigation.state.params;
if (editChannelUrl) { if (editChannelUrl) {
isEditMode = true; isEditMode = true;
this.setState({ editChannelUrl, currentPhase: Constants.PHASE_CREATE }); this.setState({ editChannelUrl, currentPhase: Constants.PHASE_CREATE });
} }
this.setState({ returnUrl });
} }
if (!isEditMode && hasFormState) { if (!isEditMode && hasFormState) {
@ -280,7 +267,7 @@ export default class ChannelCreator extends React.PureComponent {
handleCreateCancel = () => { handleCreateCancel = () => {
const { clearChannelFormState } = this.props; const { clearChannelFormState } = this.props;
clearChannelFormState(); // explicitly clear state on cancel? clearChannelFormState(); // explicitly clear state on cancel?
this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.01 }); this.setState({ showCreateChannel: false, newChannelName: '', newChannelBid: 0.1 });
}; };
handlePickerValueChange = (itemValue, itemIndex) => { handlePickerValueChange = (itemValue, itemIndex) => {
@ -589,7 +576,7 @@ export default class ChannelCreator extends React.PureComponent {
channelNameUserEdited: false, channelNameUserEdited: false,
newChannelTitle: '', newChannelTitle: '',
newChannelName: '', newChannelName: '',
newChannelBid: 0.01, newChannelBid: 0.1,
addingChannel: false, addingChannel: false,
creatingChannel: false, creatingChannel: false,
newChannelNameError: '', newChannelNameError: '',
@ -800,15 +787,7 @@ export default class ChannelCreator extends React.PureComponent {
}; };
render() { render() {
const { const { abandoningClaimIds, balance, fetchingChannels, updatingChannel, channels = [], navigation } = this.props;
abandoningClaimIds,
balance,
fetchingChannels,
sdkReady,
updatingChannel,
channels = [],
navigation,
} = this.props;
const { const {
autoStyle, autoStyle,
autoStyles, autoStyles,
@ -832,19 +811,6 @@ export default class ChannelCreator extends React.PureComponent {
const hasChannels = channels && channels.length > 0; const hasChannels = channels && channels.length > 0;
if (!sdkReady) {
return (
<View style={channelCreatorStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
return ( return (
<View style={channelCreatorStyle.container}> <View style={channelCreatorStyle.container}>
<UriBar <UriBar

View file

@ -13,7 +13,7 @@ import {
} from 'lbryinc'; } from 'lbryinc';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetClientSetting, doSetSortByItem, doSetTimeItem } from 'redux/actions/settings'; import { doSetClientSetting, doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { makeSelectClientSetting, selectSdkReady, selectSortByItem, selectTimeItem } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import DiscoverPage from './view'; import DiscoverPage from './view';
@ -27,7 +27,6 @@ const select = state => ({
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
ratingReminderDisabled: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_DISABLED)(state), ratingReminderDisabled: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_DISABLED)(state),
ratingReminderLastShown: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_LAST_SHOWN)(state), ratingReminderLastShown: makeSelectClientSetting(Constants.SETTING_RATING_REMINDER_LAST_SHOWN)(state),
sdkReady: selectSdkReady(state),
sortByItem: selectSortByItem(state), sortByItem: selectSortByItem(state),
timeItem: selectTimeItem(state), timeItem: selectTimeItem(state),
unreadSubscriptions: selectUnreadSubscriptions(state), unreadSubscriptions: selectUnreadSubscriptions(state),
@ -47,4 +46,7 @@ const perform = dispatch => ({
setTimeItem: item => dispatch(doSetTimeItem(item)), setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect(select, perform)(DiscoverPage); export default connect(
select,
perform,
)(DiscoverPage);

View file

@ -23,7 +23,6 @@ import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from 'component/link';
import ModalTagSelector from 'component/modalTagSelector'; import ModalTagSelector from 'component/modalTagSelector';
import ModalPicker from 'component/modalPicker'; import ModalPicker from 'component/modalPicker';
import SdkLoadingStatus from 'component/sdkLoadingStatus';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import _ from 'lodash'; import _ from 'lodash';
@ -38,6 +37,29 @@ class DiscoverPage extends React.PureComponent {
}; };
componentDidMount() { componentDidMount() {
// Track the total time taken if this is the first launch
AsyncStorage.getItem('firstLaunchTime').then(startTime => {
if (startTime !== null && !isNaN(parseInt(startTime, 10))) {
// We don't need this value anymore once we've retrieved it
AsyncStorage.removeItem('firstLaunchTime');
// We know this is the first app launch because firstLaunchTime is set and it"s a valid number
const start = parseInt(startTime, 10);
const now = moment().unix();
const delta = now - start;
AsyncStorage.getItem('firstLaunchSuspended').then(suspended => {
AsyncStorage.removeItem('firstLaunchSuspended');
const appSuspended = suspended === 'true';
if (NativeModules.Firebase) {
NativeModules.Firebase.track('first_run_time', {
total_seconds: delta,
app_suspended: appSuspended,
});
}
});
}
});
const { sortByItem, fetchRewardedContent, fileList, followedTags } = this.props; const { sortByItem, fetchRewardedContent, fileList, followedTags } = this.props;
this.buildTagCollection(followedTags); this.buildTagCollection(followedTags);
@ -64,8 +86,8 @@ class DiscoverPage extends React.PureComponent {
} }
onComponentFocused = () => { onComponentFocused = () => {
const { pushDrawerStack, setPlayerVisible, currentRoute } = this.props; const { pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack(); // pushDrawerStack();
NativeModules.Firebase.setCurrentScreen('Your tags'); NativeModules.Firebase.setCurrentScreen('Your tags');
setPlayerVisible(); setPlayerVisible();
@ -269,8 +291,8 @@ class DiscoverPage extends React.PureComponent {
); );
render() { render() {
const { currentRoute, navigation, sdkReady, sortByItem, timeItem } = this.props; const { currentRoute, navigation, sortByItem, timeItem } = this.props;
const { showModalTagSelector, showSortPicker, showTimePicker } = this.state; const { orderBy, showModalTagSelector, showSortPicker, showTimePicker } = this.state;
return ( return (
<View style={discoverStyle.container}> <View style={discoverStyle.container}>
@ -290,7 +312,7 @@ class DiscoverPage extends React.PureComponent {
keyExtractor={(item, index) => item} keyExtractor={(item, index) => item}
/> />
)} )}
{sdkReady && !showModalTagSelector && !showSortPicker && !showTimePicker && ( {!showModalTagSelector && !showSortPicker && !showTimePicker && (
<FloatingWalletBalance navigation={navigation} /> <FloatingWalletBalance navigation={navigation} />
)} )}
{showModalTagSelector && ( {showModalTagSelector && (
@ -317,8 +339,6 @@ class DiscoverPage extends React.PureComponent {
items={Constants.CLAIM_SEARCH_TIME_ITEMS} items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/> />
)} )}
{!sdkReady && <SdkLoadingStatus />}
</View> </View>
); );
} }

View file

@ -11,17 +11,15 @@ import {
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doDeleteFile } from 'redux/actions/file'; import { doDeleteFile } from 'redux/actions/file';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import { selectSdkReady } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import DownloadsPage from './view'; import DownloadsPage from './view';
const select = state => ({ const select = state => ({
claims: selectMyClaimsWithoutChannels(state), claims: selectMyClaimsWithoutChannels(state),
currentRoute: selectCurrentRoute(state), currentRoute: selectCurrentRoute(state),
downloadedUris: selectDownloadedUris(state),
fileInfos: selectFileInfosDownloaded(state), fileInfos: selectFileInfosDownloaded(state),
downloadedUris: selectDownloadedUris(state),
fetching: selectIsFetchingFileList(state) || selectIsFetchingClaimListMine(state), fetching: selectIsFetchingFileList(state) || selectIsFetchingClaimListMine(state),
sdkReady: selectSdkReady(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -34,4 +32,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(DownloadsPage); export default connect(
select,
perform
)(DownloadsPage);

View file

@ -144,24 +144,11 @@ class DownloadsPage extends React.PureComponent {
}; };
render() { render() {
const { downloadedUris, fetching, navigation, sdkReady } = this.props; const { fetching, claims, downloadedUris, fileInfos, navigation } = this.props;
const { selectionMode, selectedUris } = this.state; const { selectionMode, selectedUris } = this.state;
const filteredUris = this.getFilteredUris(); const filteredUris = this.getFilteredUris();
const hasDownloads = filteredUris && filteredUris.length > 0; const hasDownloads = filteredUris && filteredUris.length > 0;
if (!sdkReady) {
return (
<View style={downloadsStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
return ( return (
<View style={downloadsStyle.container}> <View style={downloadsStyle.container}>
<UriBar <UriBar

View file

@ -41,7 +41,6 @@ import { doDeleteFile, doStopDownloadingFile } from 'redux/actions/file';
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doToggleFullscreenMode } from 'redux/actions/settings'; import { doToggleFullscreenMode } from 'redux/actions/settings';
import { selectDrawerStack, makeSelectPlayerVisible } from 'redux/selectors/drawer'; import { selectDrawerStack, makeSelectPlayerVisible } from 'redux/selectors/drawer';
import { selectSdkReady } from 'redux/selectors/settings';
import FilePage from './view'; import FilePage from './view';
const select = (state, props) => { const select = (state, props) => {
@ -67,7 +66,6 @@ const select = (state, props) => {
failedPurchaseUris: selectFailedPurchaseUris(state), failedPurchaseUris: selectFailedPurchaseUris(state),
myClaimUris: selectMyClaimUrisWithoutChannels(state), myClaimUris: selectMyClaimUrisWithoutChannels(state),
purchaseUriErrorMessage: selectPurchaseUriErrorMessage(state), purchaseUriErrorMessage: selectPurchaseUriErrorMessage(state),
sdkReady: selectSdkReady(state),
streamingUrl: makeSelectStreamingUrlForUri(contentUri)(state), streamingUrl: makeSelectStreamingUrlForUri(contentUri)(state),
thumbnail: makeSelectThumbnailForUri(contentUri)(state), thumbnail: makeSelectThumbnailForUri(contentUri)(state),
title: makeSelectTitleForUri(contentUri)(state), title: makeSelectTitleForUri(contentUri)(state),
@ -84,7 +82,7 @@ const perform = dispatch => ({
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)), fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)), fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
fetchMyClaims: () => dispatch(doFetchClaimListMine()), fetchMyClaims: () => dispatch(doFetchClaimListMine()),
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
fetchViewCount: claimId => dispatch(doFetchViewCount(claimId)), fetchViewCount: claimId => dispatch(doFetchViewCount(claimId)),
fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)), fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)),
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
@ -101,4 +99,7 @@ const perform = dispatch => ({
toggleFullscreenMode: mode => dispatch(doToggleFullscreenMode(mode)), toggleFullscreenMode: mode => dispatch(doToggleFullscreenMode(mode)),
}); });
export default connect(select, perform)(FilePage); export default connect(
select,
perform,
)(FilePage);

View file

@ -37,13 +37,13 @@ import FilePrice from 'component/filePrice';
import FloatingWalletBalance from 'component/floatingWalletBalance'; import FloatingWalletBalance from 'component/floatingWalletBalance';
import Link from 'component/link'; import Link from 'component/link';
import MediaPlayer from 'component/mediaPlayer'; import MediaPlayer from 'component/mediaPlayer';
import ModalRepostView from 'component/modalRepostView';
import ModalTipView from 'component/modalTipView'; import ModalTipView from 'component/modalTipView';
import ProgressCircle from 'react-native-progress-circle'; import ProgressCircle from 'react-native-progress-circle';
import RelatedContent from 'component/relatedContent'; import RelatedContent from 'component/relatedContent';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';
import SubscribeNotificationButton from 'component/subscribeNotificationButton'; import SubscribeNotificationButton from 'component/subscribeNotificationButton';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import Video from 'react-native-video';
import FileRewardsDriver from 'component/fileRewardsDriver'; import FileRewardsDriver from 'component/fileRewardsDriver';
import filePageStyle from 'styles/filePage'; import filePageStyle from 'styles/filePage';
import uriBarStyle from 'styles/uriBar'; import uriBarStyle from 'styles/uriBar';
@ -73,7 +73,7 @@ class FilePage extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
autoGetAttempted: false, attemptAutoGet: false,
autoOpened: false, autoOpened: false,
autoDownloadStarted: false, autoDownloadStarted: false,
autoPlayMedia: false, autoPlayMedia: false,
@ -95,7 +95,6 @@ class FilePage extends React.PureComponent {
showImageViewer: false, showImageViewer: false,
showWebView: false, showWebView: false,
showTipView: false, showTipView: false,
showRepostView: false,
playbackStarted: false, playbackStarted: false,
playerBgHeight: 0, playerBgHeight: 0,
playerHeight: 0, playerHeight: 0,
@ -105,8 +104,6 @@ class FilePage extends React.PureComponent {
stopDownloadConfirmed: false, stopDownloadConfirmed: false,
streamingMode: false, streamingMode: false,
viewCountFetched: false, viewCountFetched: false,
isRepost: false,
uriPushedToDrawerStack: false,
}; };
} }
@ -117,22 +114,6 @@ class FilePage extends React.PureComponent {
// this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); // this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused);
} }
checkRepost = () => {
const { claim, isResolvingUri, navigation, pushDrawerStack } = this.props;
const { uri } = this.state;
if (!isResolvingUri) {
if (claim && claim.repost_url) {
// redirect to canonical url
this.setState({ isRepost: true });
navigateToUri(navigation, claim.canonical_url, null, false, claim.permanent_url, false, true);
} else {
this.setState({ uriPushedToDrawerStack: true }, () => {
pushDrawerStack(uri);
});
}
}
};
onComponentFocused = () => { onComponentFocused = () => {
StatusBar.setHidden(false); StatusBar.setHidden(false);
NativeModules.Firebase.setCurrentScreen('File').then(result => { NativeModules.Firebase.setCurrentScreen('File').then(result => {
@ -149,8 +130,6 @@ class FilePage extends React.PureComponent {
setPlayerVisible(true, uri); setPlayerVisible(true, uri);
if (!isResolvingUri && !claim) resolveUri(uri); if (!isResolvingUri && !claim) resolveUri(uri);
this.checkRepost();
this.fetchFileInfo(uri, this.props); this.fetchFileInfo(uri, this.props);
this.fetchCostInfo(uri, this.props); this.fetchCostInfo(uri, this.props);
@ -267,7 +246,6 @@ class FilePage extends React.PureComponent {
'playerBgHeighht', 'playerBgHeighht',
'playerHeight', 'playerHeight',
'relatedY', 'relatedY',
'showRepostView',
'showTipView', 'showTipView',
'showImageViewer', 'showImageViewer',
'showWebView', 'showWebView',
@ -299,27 +277,12 @@ class FilePage extends React.PureComponent {
} }
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
const { const { claim, contentType, costInfo, fileInfo, isResolvingUri, resolveUri, navigation, title } = this.props;
claim,
contentType,
costInfo,
fileInfo,
isResolvingUri,
resolveUri,
sdkReady,
navigation,
title,
} = this.props;
const { uri } = this.state; const { uri } = this.state;
if (!isResolvingUri && claim === undefined && uri) { if (!isResolvingUri && claim === undefined && uri) {
resolveUri(uri); resolveUri(uri);
} }
if (!prevProps.claim && claim) {
this.checkRepost();
return;
}
// Returned to the page. If mediaLoaded, and currentMediaInfo is different, update // Returned to the page. If mediaLoaded, and currentMediaInfo is different, update
if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) { if (this.state.mediaLoaded && window.currentMediaInfo && window.currentMediaInfo.uri !== this.state.uri) {
const { metadata } = this.props; const { metadata } = this.props;
@ -335,12 +298,10 @@ class FilePage extends React.PureComponent {
const isPlayable = mediaType === 'video' || mediaType === 'audio'; const isPlayable = mediaType === 'video' || mediaType === 'audio';
const isViewable = mediaType === 'image' || mediaType === 'text'; const isViewable = mediaType === 'image' || mediaType === 'text';
if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) { if (claim && costInfo && costInfo.cost === 0 && !this.state.autoGetAttempted && isViewable) {
this.setState({ autoGetAttempted: true }, () => { this.setState({ autoGetAttempted: true }, () => this.checkStoragePermissionForDownload());
this.checkStoragePermissionForDownload();
});
} }
if (((costInfo && costInfo.cost > 0) || !isPlayable) && !fileInfo && !isViewable && !this.state.showRecommended) { if (((costInfo && costInfo.cost > 0) || !isPlayable) && (!fileInfo && !isViewable) && !this.state.showRecommended) {
this.setState({ showRecommended: true }); this.setState({ showRecommended: true });
} }
@ -399,11 +360,7 @@ class FilePage extends React.PureComponent {
onEditPressed = () => { onEditPressed = () => {
const { claim, navigation } = this.props; const { claim, navigation } = this.props;
const uri = this.state.uri || this.getPurchaseUrl(); navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH, params: { editMode: true, claimToEdit: claim } });
navigation.navigate({
routeName: Constants.DRAWER_ROUTE_PUBLISH,
params: { editMode: true, claimToEdit: claim, returnUrl: uri },
});
}; };
onDeletePressed = () => { onDeletePressed = () => {
@ -649,7 +606,7 @@ class FilePage extends React.PureComponent {
let timeToStartMillis, timeToStart; let timeToStartMillis, timeToStart;
if (this.startTime) { if (this.startTime) {
timeToStartMillis = Date.now() - this.startTime; timeToStartMillis = Date.now() - this.startTime;
timeToStart = Math.ceil(timeToStartMillis / 1000.0); timeToStart = Math.ceil(timeToStartMillis / 1000);
this.startTime = null; this.startTime = null;
} }
@ -659,8 +616,8 @@ class FilePage extends React.PureComponent {
let payload = { uri: uri }; let payload = { uri: uri };
if (!isNaN(timeToStart)) { if (!isNaN(timeToStart)) {
payload['time_to_start_seconds'] = parseInt(timeToStart, 10); payload['time_to_start_seconds'] = timeToStart;
payload['time_to_start_ms'] = parseInt(timeToStartMillis, 10); payload['time_to_start_ms'] = timeToStartMillis;
} }
NativeModules.Firebase.track('play', payload); NativeModules.Firebase.track('play', payload);
@ -720,7 +677,7 @@ class FilePage extends React.PureComponent {
}; };
confirmPurchaseUri = (uri, costInfo, download) => { confirmPurchaseUri = (uri, costInfo, download) => {
const { notify, purchaseUri, sdkReady, title } = this.props; const { notify, purchaseUri, title } = this.props;
if (!costInfo) { if (!costInfo) {
notify({ message: __('This content cannot be viewed at this time. Please try again in a bit.'), isError: true }); notify({ message: __('This content cannot be viewed at this time. Please try again in a bit.'), isError: true });
this.setState({ downloadPressed: false }); this.setState({ downloadPressed: false });
@ -729,11 +686,6 @@ class FilePage extends React.PureComponent {
} }
const { cost } = costInfo; const { cost } = costInfo;
if (!NativeModules.UtilityModule.dhtEnabled && !sdkReady && parseFloat(cost) === 0) {
this.attemptLbryTvPlayback();
return;
}
if (costInfo.cost > 0) { if (costInfo.cost > 0) {
Alert.alert( Alert.alert(
__('Confirm Purchase'), __('Confirm Purchase'),
@ -746,56 +698,34 @@ class FilePage extends React.PureComponent {
[ [
{ {
text: __('OK'), text: __('OK'),
onPress: () => { onPress: () => purchaseUri(uri, costInfo, download),
this.startTime = Date.now();
purchaseUri(uri, costInfo, download);
},
}, },
{ text: __('Cancel') }, { text: __('Cancel') },
], ],
); );
} else { } else {
// Free content. Just call purchaseUri directly. // Free content. Just call purchaseUri directly.
this.startTime = Date.now();
purchaseUri(uri, costInfo, download); purchaseUri(uri, costInfo, download);
} }
}; };
getStreamUrlForClaim = claim => {
const { name, claim_id: claimId } = claim;
return `https://player.lbry.tv/content/claims/${name}/${claimId}/stream`;
};
attemptLbryTvPlayback = () => {
const { claim } = this.props;
if (claim) {
this.setState({ streamingMode: true, currentStreamUrl: this.getStreamUrlForClaim(claim) });
}
};
onFileDownloadButtonPressed = () => { onFileDownloadButtonPressed = () => {
this.startTime = Date.now(); const { claim, costInfo, contentType, purchaseUri, setPlayerVisible } = this.props;
const { claim, costInfo, contentType, notify, sdkReady, setPlayerVisible } = this.props;
const mediaType = Lbry.getMediaType(contentType); const mediaType = Lbry.getMediaType(contentType);
const isPlayable = mediaType === 'video' || mediaType === 'audio'; const isPlayable = mediaType === 'video' || mediaType === 'audio';
const isViewable = mediaType === 'image' || mediaType === 'text'; const isViewable = mediaType === 'image' || mediaType === 'text';
const purchaseUrl = this.getPurchaseUrl(); const purchaseUrl = this.getPurchaseUrl();
NativeModules.Firebase.track('purchase_uri', { uri: purchaseUrl });
if (!isPlayable) { if (!isPlayable) {
if (!sdkReady) {
notify({
message: __('The LBRY background service is still initializing. Please wait a few moments and try again.'),
});
return;
}
this.onDownloadPressed(); this.onDownloadPressed();
} else { } else {
this.confirmPurchaseUri(purchaseUrl, costInfo, !isPlayable); this.confirmPurchaseUri(purchaseUrl, costInfo, !isPlayable);
} }
NativeModules.Firebase.track('purchase_uri', { uri: purchaseUrl });
if (isPlayable) { if (isPlayable) {
this.startTime = Date.now();
this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false }); this.setState({ downloadPressed: true, autoPlayMedia: true, stopDownloadConfirmed: false });
} }
if (isViewable) { if (isViewable) {
@ -820,16 +750,7 @@ class FilePage extends React.PureComponent {
}; };
onDownloadPressed = () => { onDownloadPressed = () => {
const { claim, notify, sdkReady, title } = this.props; const { claim, title } = this.props;
if (!sdkReady) {
notify({
message: __(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
),
});
return;
}
const fileSize = claim && claim.value && claim.value.source ? claim.value.source.size : 0; const fileSize = claim && claim.value && claim.value.source ? claim.value.source.size : 0;
Alert.alert( Alert.alert(
__('Download file'), __('Download file'),
@ -1029,6 +950,7 @@ class FilePage extends React.PureComponent {
myClaimUris, myClaimUris,
navigation, navigation,
position, position,
purchaseUri,
pushDrawerStack, pushDrawerStack,
setPlayerVisible, setPlayerVisible,
thumbnail, thumbnail,
@ -1043,12 +965,6 @@ class FilePage extends React.PureComponent {
let innerContent = null; let innerContent = null;
if ((isResolvingUri && !claim) || !claim) { if ((isResolvingUri && !claim) || !claim) {
if (!isResolvingUri && !claim && !this.state.uriPushedToDrawerStack) {
this.setState({ uriPushedToDrawerStack: true }, () => {
pushDrawerStack(uri);
});
}
return ( return (
<View style={filePageStyle.pageContainer}> <View style={filePageStyle.pageContainer}>
<UriBar value={uri} navigation={navigation} /> <UriBar value={uri} navigation={navigation} />
@ -1117,17 +1033,6 @@ class FilePage extends React.PureComponent {
tags = claim.value.tags; tags = claim.value.tags;
} }
if (!isResolvingUri && this.state.isRepost) {
return null;
}
// in case we somehow get here without the uri pushed to the drawer stack
if (!isResolvingUri && !this.state.isRepost && !this.state.uriPushedToDrawerStack) {
this.setState({ uriPushedToDrawerStack: true }, () => {
pushDrawerStack(uri);
});
}
const completed = fileInfo && fileInfo.completed; const completed = fileInfo && fileInfo.completed;
const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id); const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id);
const description = metadata.description ? metadata.description : null; const description = metadata.description ? metadata.description : null;
@ -1138,8 +1043,7 @@ class FilePage extends React.PureComponent {
const channelName = signingChannel && signingChannel.name; const channelName = signingChannel && signingChannel.name;
const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id; const channelClaimId = claim && claim.signing_channel && claim.signing_channel.claim_id;
const fullUri = `${claim.name}#${claim.claim_id}`; const fullUri = `${claim.name}#${claim.claim_id}`;
const canEdit = const canEdit = myClaimUris.includes(normalizeURI(fullUri));
myClaimUris.includes(normalizeURI(fullUri)) || myClaimUris.includes(normalizeURI(claim.canonical_url));
const showActions = const showActions =
(canEdit || (fileInfo && fileInfo.download_path)) && (canEdit || (fileInfo && fileInfo.download_path)) &&
!this.state.fullscreenMode && !this.state.fullscreenMode &&
@ -1223,7 +1127,7 @@ class FilePage extends React.PureComponent {
style={filePageStyle.mediaContainer} style={filePageStyle.mediaContainer}
onPress={this.onFileDownloadButtonPressed} onPress={this.onFileDownloadButtonPressed}
> >
{(canOpen || !fileInfo || (isPlayable && !canLoadMedia) || (!canOpen && fileInfo)) && ( {(canOpen || (!fileInfo || (isPlayable && !canLoadMedia)) || (!canOpen && fileInfo)) && (
<FileItemMedia <FileItemMedia
duration={duration} duration={duration}
style={filePageStyle.thumbnail} style={filePageStyle.thumbnail}
@ -1360,14 +1264,6 @@ class FilePage extends React.PureComponent {
<Text style={filePageStyle.largeButtonText}>{__('Share')}</Text> <Text style={filePageStyle.largeButtonText}>{__('Share')}</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity
style={filePageStyle.largeButton}
onPress={() => this.setState({ showRepostView: true })}
>
<Icon name={'retweet'} size={16} style={filePageStyle.largeButtonIcon} />
<Text style={filePageStyle.largeButtonText}>{__('Repost')}</Text>
</TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={filePageStyle.largeButton} style={filePageStyle.largeButton}
onPress={() => this.setState({ showTipView: true })} onPress={() => this.setState({ showTipView: true })}
@ -1542,17 +1438,7 @@ class FilePage extends React.PureComponent {
onSendTipSuccessful={() => this.setState({ showTipView: false })} onSendTipSuccessful={() => this.setState({ showTipView: false })}
/> />
)} )}
{this.state.showRepostView && (
<ModalRepostView
claim={claim}
title={title}
onCancelPress={() => this.setState({ showRepostView: false })}
onOverlayPress={() => this.setState({ showRepostView: false })}
onRepostSuccessful={() => this.setState({ showRepostView: false })}
/>
)}
{!this.state.fullscreenMode && {!this.state.fullscreenMode &&
!this.state.showRepostView &&
!this.state.showTipView && !this.state.showTipView &&
!this.state.showImageViewer && !this.state.showImageViewer &&
!this.state.showWebView && <FloatingWalletBalance navigation={navigation} />} !this.state.showWebView && <FloatingWalletBalance navigation={navigation} />}

View file

@ -12,26 +12,27 @@ import {
doFetchInviteStatus, doFetchInviteStatus,
doUserInviteNew, doUserInviteNew,
} from 'lbryinc'; } from 'lbryinc';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { selectSdkReady } from 'redux/selectors/settings'; import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form';
import { selectDrawerStack } from 'redux/selectors/drawer';
import { selectChannelFormState, selectHasChannelFormState } from 'redux/selectors/form';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import InvitesPage from './view'; import InvitesPage from './view';
const select = state => ({ const select = state => ({
channels: selectMyChannelClaims(state), channels: selectMyChannelClaims(state),
errorMessage: selectUserInviteNewErrorMessage(state),
fetchingChannels: selectFetchingMyChannels(state), fetchingChannels: selectFetchingMyChannels(state),
fetchingInvitees: selectUserInviteStatusIsPending(state), fetchingInvitees: selectUserInviteStatusIsPending(state),
invitees: selectUserInvitees(state), errorMessage: selectUserInviteNewErrorMessage(state),
invitesRemaining: selectUserInvitesRemaining(state), invitesRemaining: selectUserInvitesRemaining(state),
isPending: selectUserInviteNewIsPending(state),
referralCode: selectUserInviteReferralCode(state), referralCode: selectUserInviteReferralCode(state),
isPending: selectUserInviteNewIsPending(state),
invitees: selectUserInvitees(state),
referralReward: selectReferralReward(state), referralReward: selectReferralReward(state),
sdkReady: selectSdkReady(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
fetchChannelListMine: () => dispatch(doFetchChannelListMine(1, 99999, true)), fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
fetchInviteStatus: () => dispatch(doFetchInviteStatus()), fetchInviteStatus: () => dispatch(doFetchInviteStatus()),
inviteNew: email => dispatch(doUserInviteNew(email)), inviteNew: email => dispatch(doUserInviteNew(email)),
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_INVITES)), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_INVITES)),
@ -39,4 +40,7 @@ const perform = dispatch => ({
notify: data => dispatch(doToast(data)), notify: data => dispatch(doToast(data)),
}); });
export default connect(select, perform)(InvitesPage); export default connect(
select,
perform,
)(InvitesPage);

View file

@ -11,13 +11,16 @@ import {
View, View,
} from 'react-native'; } from 'react-native';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import Button from 'component/button'; import Button from 'component/button';
import ChannelSelector from 'component/channelSelector'; import ChannelSelector from 'component/channelSelector';
import EmptyStateView from 'component/emptyStateView'; import PageHeader from 'component/pageHeader';
import RewardCard from 'component/rewardCard';
import RewardEnrolment from 'component/rewardEnrolment';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import invitesStyle from 'styles/invites'; import invitesStyle from 'styles/invites';
import { fetchReferralCode, logPublish } from 'utils/helper';
class InvitesPage extends React.PureComponent { class InvitesPage extends React.PureComponent {
state = { state = {
@ -44,19 +47,7 @@ class InvitesPage extends React.PureComponent {
pushDrawerStack(); pushDrawerStack();
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Invites').then(result => { NativeModules.Firebase.setCurrentScreen('Invites').then(result => {
fetchReferralCode( fetchChannelListMine();
response => {
if (response && response.length > 0) {
// only need to use the first referral code.
// inviteLink will be updated after channels are loaded (if the user has created at least one channel)
this.setState({ inviteLink: `https://lbry.tv/$/invite/${response[0]}` });
}
fetchChannelListMine();
},
error => {
fetchChannelListMine();
},
);
fetchInviteStatus(); fetchInviteStatus();
}); });
}; };
@ -71,15 +62,13 @@ class InvitesPage extends React.PureComponent {
const filtered = channels.filter(c => c.name === channelName); const filtered = channels.filter(c => c.name === channelName);
if (filtered.length > 0) { if (filtered.length > 0) {
const channel = filtered[0]; const channel = filtered[0];
logPublish(channel);
this.setState({ channelName, inviteLink: this.getLinkForChannel(channel) }); this.setState({ channelName, inviteLink: this.getLinkForChannel(channel) });
} }
} }
}; };
getLinkForChannel = channel => { getLinkForChannel = channel => {
const parsedUrl = channel.canonical_url ? parseURI(channel.canonical_url) : parseURI(channel.permanent_url); const { claimId, claimName } = parseURI(channel.permanent_url);
const { claimId, claimName } = parsedUrl;
return `https://lbry.tv/$/invite/${claimName}:${claimId}`; return `https://lbry.tv/$/invite/${claimName}:${claimId}`;
}; };
@ -107,7 +96,6 @@ class InvitesPage extends React.PureComponent {
if (!this.state.channelName && channels && channels.length > 0) { if (!this.state.channelName && channels && channels.length > 0) {
const firstChannel = channels[0]; const firstChannel = channels[0];
logPublish(firstChannel);
this.setState({ channelName: firstChannel.name, inviteLink: this.getLinkForChannel(firstChannel) }); this.setState({ channelName: firstChannel.name, inviteLink: this.getLinkForChannel(firstChannel) });
} }
@ -130,23 +118,10 @@ class InvitesPage extends React.PureComponent {
}; };
render() { render() {
const { fetchingInvitees, invitees, isPending, navigation, sdkReady } = this.props; const { fetchingInvitees, user, navigation, notify, isPending, invitees } = this.props;
const { email } = this.state; const { email, inviteLink } = this.state;
const hasInvitees = invitees && invitees.length > 0; const hasInvitees = invitees && invitees.length > 0;
if (!sdkReady) {
return (
<View style={invitesStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
return ( return (
<View style={invitesStyle.container}> <View style={invitesStyle.container}>
<UriBar navigation={navigation} /> <UriBar navigation={navigation} />

View file

@ -1,28 +0,0 @@
import { connect } from 'react-redux';
import { makeSelectContentPositionForUri, selectBalance } from 'lbry-redux';
import { doClaimEligiblePurchaseRewards, makeSelectViewCountForUri, selectRewardContentClaimIds } from 'lbryinc';
import { doSetPlayerVisible } from 'redux/actions/drawer';
import { makeSelectPlayerVisible } from 'redux/selectors/drawer';
import { doToggleFullscreenMode } from 'redux/actions/settings';
import LiteFilePage from './view';
const select = (state, props) => {
const { uri, fullUri } = props.navigation.state.params;
const contentUri = fullUri || uri;
const selectProps = { uri: contentUri };
return {
balance: selectBalance(state),
isPlayerVisible: makeSelectPlayerVisible(uri)(state), // use navigation uri for this selector
position: makeSelectContentPositionForUri(contentUri)(state),
viewCount: makeSelectViewCountForUri(contentUri)(state),
rewardedContentClaimIds: selectRewardContentClaimIds(state),
};
};
const perform = dispatch => ({
claimEligibleRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
setPlayerVisible: (visible, uri) => dispatch(doSetPlayerVisible(visible, uri)),
toggleFullscreenMode: mode => dispatch(doToggleFullscreenMode(mode)),
});
export default connect(select, perform)(LiteFilePage);

View file

@ -1,297 +0,0 @@
import React from 'react';
import { Lbry, formatCredits, normalizeURI, parseURI, parseQueryParams } from 'lbry-redux';
import { Lbryio } from 'lbryinc';
import {
ActivityIndicator,
Alert,
DeviceEventEmitter,
Dimensions,
Image,
Linking,
NativeModules,
Platform,
ScrollView,
StatusBar,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
TouchableWithoutFeedback,
View,
} from 'react-native';
import UriBar from 'component/uriBar';
import Link from 'component/link';
import MediaPlayer from 'component/mediaPlayer';
import RelatedContent from 'component/relatedContent';
import filePageStyle from 'styles/filePage';
import { decode, formatLbryUrlForWeb, navigateToUri } from 'utils/helper';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import uriBarStyle from 'styles/uriBar';
import { NavigationActions, StackActions } from 'react-navigation';
// This page will only be used for playing audio / video content from a remote stream URL
class LiteFilePage extends React.PureComponent {
playerBackground = null;
scrollView = null;
player = null;
startTime = null;
state = {
channelName: null,
channelUrl: null,
fileViewLogged: false,
fullscreenMode: false,
playbackStarted: false,
playerHeight: null,
isLandscape: false,
sdkReady: false, // TODO: progressively enable features (e.g. tip) when sdk is ready
showRecommended: false,
title: null,
viewCount: 0,
};
checkOrientation = () => {
if (this.state.fullscreenMode) {
return;
}
const screenDimension = Dimensions.get('window');
const screenWidth = screenDimension.width;
const screenHeight = screenDimension.height;
const isLandscape = screenWidth > screenHeight;
this.setState({ isLandscape });
if (!this.playerBackground) {
return;
}
if (isLandscape) {
this.playerBackground.setNativeProps({
height: screenHeight - StyleSheet.flatten(uriBarStyle.uriContainer).height,
});
} else if (this.state.playerBgHeight > 0) {
this.playerBackground.setNativeProps({ height: this.state.playerBgHeight });
}
};
handleFullscreenToggle = isFullscreen => {
const { toggleFullscreenMode } = this.props;
toggleFullscreenMode(isFullscreen);
if (isFullscreen) {
// fullscreen, so change orientation to landscape mode
NativeModules.ScreenOrientation.lockOrientationLandscape();
// hide the navigation bar (on devices that have the soft navigation bar)
NativeModules.UtilityModule.hideNavigationBar();
} else {
// Switch back to portrait mode when the media is not fullscreen
NativeModules.ScreenOrientation.lockOrientationPortrait();
// show the navigation bar (on devices that have the soft navigation bar)
NativeModules.UtilityModule.showNavigationBar();
}
this.setState({ fullscreenMode: isFullscreen });
StatusBar.setHidden(isFullscreen);
};
getStreamUrl = url => {
const { claimName, claimId } = parseURI(url);
return `https://player.lbry.tv/content/claims/${claimName}/${claimId}/stream`;
};
handleSharePress = url => {
const shareUrl = Constants.SHARE_BASE_URL + formatLbryUrlForWeb(url);
NativeModules.UtilityModule.shareUrl(shareUrl);
};
handleOpenUrl = url => {
const { navigation } = this.props;
Alert.alert(
__('Stop watching?'),
'The LBRY service is still loading stuff in the background. Would you like to continue?',
[
{ text: __('No') },
{
text: __('Yes'),
onPress: () => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Splash', params: { resetUrl: url } })],
});
navigation.dispatch(resetAction);
},
},
],
);
};
componentDidMount() {
this.startTime = Date.now();
}
componentDidUpdate() {
const { navigation } = this.props;
const { uri } = navigation.state.params;
if (!this.state.title) {
const params = parseQueryParams(uri);
const { channelUrl, contentTitle } = params;
const channelName = channelUrl ? parseURI(decode(channelUrl)).claimName : null;
this.setState({
title: decode(contentTitle),
channelUrl,
channelName,
showRecommended: true,
});
}
}
render() {
const { navigation, rewardedContentClaimIds } = this.props;
const { channelName, channelUrl, title, sdkReady, viewCount } = this.state;
const { uri } = navigation.state.params;
const { claimName, claimId } = parseURI(uri);
const isRewardContent = rewardedContentClaimIds.includes(claimId);
const playerBgStyle = [filePageStyle.playerBackground, filePageStyle.containedPlayerBackground];
const fsPlayerBgStyle = [filePageStyle.playerBackground, filePageStyle.fullscreenPlayerBackground];
const playerStyle = [
filePageStyle.player,
this.state.isLandscape
? filePageStyle.containedPlayerLandscape
: this.state.fullscreenMode
? filePageStyle.fullscreenPlayer
: filePageStyle.containedPlayer,
];
return (
<View style={filePageStyle.pageContainer}>
{!this.state.fullscreenMode && <UriBar value={uri.split('?')[0]} navigation={navigation} />}
<View
style={this.state.fullscreenMode ? filePageStyle.innerPageContainerFsMode : filePageStyle.innerPageContainer}
onLayout={this.checkOrientation}
>
<TouchableOpacity activeOpacity={0.5} style={filePageStyle.mediaContainer} />
<View
style={playerBgStyle}
ref={ref => {
this.playerBackground = ref;
}}
onLayout={evt => {
if (!this.state.playerBgHeight) {
this.setState({ playerBgHeight: evt.nativeEvent.layout.height });
}
}}
/>
{this.state.fullscreenMode && <View style={fsPlayerBgStyle} />}
<MediaPlayer
assignPlayer={ref => {
this.player = ref;
}}
uri={uri}
source={this.getStreamUrl(uri)}
style={playerStyle}
autoPlay
onFullscreenToggled={this.handleFullscreenToggle}
onLayout={evt => {
if (!this.state.playerHeight) {
this.setState({ playerHeight: evt.nativeEvent.layout.height });
}
}}
/>
<ScrollView
style={filePageStyle.scrollContainer}
contentContainerStyle={filePageStyle.scrollContent}
keyboardShouldPersistTaps={'handled'}
ref={ref => {
this.scrollView = ref;
}}
>
<TouchableWithoutFeedback
style={filePageStyle.titleTouch}
onPress={() => this.setState({ showDescription: !this.state.showDescription })}
>
<View style={filePageStyle.titleArea}>
<View style={filePageStyle.titleRow}>
<Text style={filePageStyle.title} selectable>
{title}
</Text>
{isRewardContent && <Icon name="award" style={filePageStyle.rewardIcon} size={16} />}
</View>
<Text style={filePageStyle.viewCount}>
{viewCount === 1 && __('%view% view', { view: viewCount })}
{viewCount > 1 && __('%view% views', { view: viewCount })}
</Text>
</View>
</TouchableWithoutFeedback>
<View style={filePageStyle.largeButtonsRow}>
<TouchableOpacity style={filePageStyle.largeButton} onPress={() => this.handleSharePress(uri)}>
<Icon name={'share-alt'} size={16} style={filePageStyle.largeButtonIcon} />
<Text style={filePageStyle.largeButtonText}>{__('Share')}</Text>
</TouchableOpacity>
{sdkReady && (
<TouchableOpacity
style={filePageStyle.largeButton}
onPress={() => this.setState({ showTipView: true })}
>
<Icon name={'gift'} size={16} style={filePageStyle.largeButtonIcon} />
<Text style={filePageStyle.largeButtonText}>{__('Tip')}</Text>
</TouchableOpacity>
)}
</View>
<View style={filePageStyle.channelRow}>
<View style={filePageStyle.publishInfo}>
{channelName && (
<Link
style={filePageStyle.channelName}
selectable
text={channelName}
numberOfLines={1}
ellipsizeMode={'tail'}
onPress={() => this.handleOpenUrl(channelUrl)}
/>
)}
{!channelName && (
<Text style={filePageStyle.anonChannelName} selectable ellipsizeMode={'tail'}>
{__('Anonymous')}
</Text>
)}
</View>
</View>
<View onLayout={this.setRelatedContentPosition} />
{this.state.showRecommended && (
<RelatedContent
navigation={navigation}
claimId={claimId}
claimName={claimName}
title={title}
urlOpenHandler={this.handleOpenUrl}
uri={uri}
fullUri={uri}
/>
)}
</ScrollView>
</View>
</View>
);
}
}
export default LiteFilePage;

View file

@ -13,7 +13,6 @@ import { selectDrawerStack } from 'redux/selectors/drawer';
import { doUpdatePublishFormState, doClearPublishFormState, doPendingPublishSuccess } from 'redux/actions/form'; import { doUpdatePublishFormState, doClearPublishFormState, doPendingPublishSuccess } from 'redux/actions/form';
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { selectPublishFormState, selectHasPublishFormState } from 'redux/selectors/form'; import { selectPublishFormState, selectHasPublishFormState } from 'redux/selectors/form';
import { selectSdkReady } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import PublishPage from './view'; import PublishPage from './view';
@ -24,7 +23,6 @@ const select = state => ({
myClaims: selectMyClaims(state), myClaims: selectMyClaims(state),
publishFormState: selectPublishFormState(state), publishFormState: selectPublishFormState(state),
publishFormValues: selectPublishFormValues(state), publishFormValues: selectPublishFormValues(state),
sdkReady: selectSdkReady(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -41,4 +39,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(PublishPage); export default connect(
select,
perform,
)(PublishPage);

View file

@ -37,7 +37,6 @@ import Button from 'component/button';
import ChannelSelector from 'component/channelSelector'; import ChannelSelector from 'component/channelSelector';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import EmptyStateView from 'component/emptyStateView';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import FloatingWalletBalance from 'component/floatingWalletBalance'; import FloatingWalletBalance from 'component/floatingWalletBalance';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
@ -48,7 +47,7 @@ import Tag from 'component/tag';
import TagSearch from 'component/tagSearch'; import TagSearch from 'component/tagSearch';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import publishStyle from 'styles/publish'; import publishStyle from 'styles/publish';
import { navigateToUri, navigateBack, logPublish, uploadImageAsset } from 'utils/helper'; import { navigateToUri, logPublish, uploadImageAsset } from 'utils/helper';
const languages = { const languages = {
en: 'English', en: 'English',
@ -121,7 +120,7 @@ class PublishPage extends React.PureComponent {
// input data // input data
hasEditedContentAddress: false, hasEditedContentAddress: false,
bid: 0.01, bid: 0.1,
description: null, description: null,
title: null, title: null,
language: 'en', language: 'en',
@ -142,8 +141,6 @@ class PublishPage extends React.PureComponent {
// other // other
publishStarted: false, publishStarted: false,
storagePermissionRequired: false, storagePermissionRequired: false,
hasReturnedBack: false,
returnUrl: null,
}; };
didFocusListener; didFocusListener;
@ -239,7 +236,7 @@ class PublishPage extends React.PureComponent {
let isEditMode = false, let isEditMode = false,
vanityUrlSet = false; vanityUrlSet = false;
if (navigation.state.params) { if (navigation.state.params) {
const { displayForm, editMode, claimToEdit, vanityUrl, returnUrl } = navigation.state.params; const { displayForm, editMode, claimToEdit, vanityUrl } = navigation.state.params;
if (editMode) { if (editMode) {
this.prepareEdit(claimToEdit); this.prepareEdit(claimToEdit);
isEditMode = true; isEditMode = true;
@ -253,7 +250,6 @@ class PublishPage extends React.PureComponent {
vanityUrl: claimName, vanityUrl: claimName,
}); });
} }
this.setState({ returnUrl });
} }
if (!isEditMode && hasFormState) { if (!isEditMode && hasFormState) {
@ -476,15 +472,7 @@ class PublishPage extends React.PureComponent {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { const { currentRoute: prevRoute, drawerStack: prevDrawerStack, notify, updatePublishFormState } = this.props;
currentRoute: prevRoute,
drawerStack: prevDrawerStack,
popDrawerStack,
setPlayerVisible,
navigation,
notify,
updatePublishFormState,
} = this.props;
const { currentRoute, drawerStack, publishFormValues } = nextProps; const { currentRoute, drawerStack, publishFormValues } = nextProps;
if (Constants.DRAWER_ROUTE_PUBLISH === currentRoute && currentRoute !== prevRoute) { if (Constants.DRAWER_ROUTE_PUBLISH === currentRoute && currentRoute !== prevRoute) {
@ -498,11 +486,6 @@ class PublishPage extends React.PureComponent {
) { ) {
// navigated back from the form // navigated back from the form
this.showSelector(); this.showSelector();
if (!this.state.hasReturnedBack && this.state.returnUrl) {
this.setState({ hasReturnedBack: true }, () => {
navigateBack(navigation, drawerStack, popDrawerStack, setPlayerVisible);
});
}
} }
} }
@ -975,7 +958,7 @@ class PublishPage extends React.PureComponent {
}; };
render() { render() {
const { balance, navigation, notify, sdkReady } = this.props; const { balance, navigation, notify, publishFormValues } = this.props;
const { const {
allThumbnailsChecked, allThumbnailsChecked,
canUseCamera, canUseCamera,
@ -988,19 +971,6 @@ class PublishPage extends React.PureComponent {
videos, videos,
} = this.state; } = this.state;
if (!sdkReady) {
return (
<View style={publishStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
let content; let content;
if (Constants.PHASE_SELECTOR === currentPhase) { if (Constants.PHASE_SELECTOR === currentPhase) {
content = ( content = (

View file

@ -9,7 +9,6 @@ import {
selectIsFetchingClaimListMine, selectIsFetchingClaimListMine,
} from 'lbry-redux'; } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { selectSdkReady } from 'redux/selectors/settings';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import PublishesPage from './view'; import PublishesPage from './view';
@ -17,7 +16,6 @@ const select = state => ({
uris: selectMyClaimUrisWithoutChannels(state), uris: selectMyClaimUrisWithoutChannels(state),
fetching: selectIsFetchingClaimListMine(state), fetching: selectIsFetchingClaimListMine(state),
pendingClaims: selectPendingClaims(state), pendingClaims: selectPendingClaims(state),
sdkReady: selectSdkReady(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -29,4 +27,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(PublishesPage); export default connect(
select,
perform
)(PublishesPage);

View file

@ -114,27 +114,14 @@ class PublishesPage extends React.PureComponent {
}, },
}, },
], ],
{ cancelable: true }, { cancelable: true }
); );
}; };
render() { render() {
const { fetching, navigation, sdkReady, uris } = this.props; const { fetching, navigation, uris } = this.props;
const { selectionMode, selectedUris } = this.state; const { selectionMode, selectedUris } = this.state;
if (!sdkReady) {
return (
<View style={publishStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
return ( return (
<View style={publishStyle.container}> <View style={publishStyle.container}>
<UriBar <UriBar
@ -194,7 +181,7 @@ class PublishesPage extends React.PureComponent {
}); });
} else { } else {
// TODO: when shortUrl is available for my claims, navigate to that URL instead // TODO: when shortUrl is available for my claims, navigate to that URL instead
navigateToUri(navigation, claim.permanent_url); navigateToUri(navigation, item);
} }
} }
}} }}

View file

@ -12,8 +12,7 @@ import {
import { doToast } from 'lbry-redux'; import { doToast } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import { selectSdkReady } from 'redux/selectors/settings'; import Constants from 'constants';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import RewardsPage from './view'; import RewardsPage from './view';
const select = state => ({ const select = state => ({
@ -23,7 +22,6 @@ const select = state => ({
emailVerifyPending: selectEmailVerifyIsPending(state), emailVerifyPending: selectEmailVerifyIsPending(state),
fetching: selectFetchingRewards(state), fetching: selectFetchingRewards(state),
rewards: selectUnclaimedRewards(state), rewards: selectUnclaimedRewards(state),
sdkReady: selectSdkReady(state),
user: selectUser(state), user: selectUser(state),
}); });
@ -35,4 +33,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(RewardsPage); export default connect(
select,
perform
)(RewardsPage);

View file

@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import { Lbryio } from 'lbryinc'; import { Lbry } from 'lbry-redux';
import { ActivityIndicator, NativeModules, ScrollView, Text, View } from 'react-native'; import { ActivityIndicator, NativeModules, ScrollView, Text, View } from 'react-native';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Link from 'component/link'; import Link from 'component/link';
import CustomRewardCard from 'component/customRewardCard'; import CustomRewardCard from 'component/customRewardCard';
import EmptyStateView from 'component/emptyStateView'; import PageHeader from 'component/pageHeader';
import RewardCard from 'component/rewardCard'; import RewardCard from 'component/rewardCard';
import RewardEnrolment from 'component/rewardEnrolment'; import RewardEnrolment from 'component/rewardEnrolment';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
@ -17,14 +17,13 @@ const FILTER_CLAIMED = 'claimed';
class RewardsPage extends React.PureComponent { class RewardsPage extends React.PureComponent {
state = { state = {
currentFilter: FILTER_AVAILABLE,
firstRewardClaimed: false,
isEmailVerified: false, isEmailVerified: false,
isIdentityVerified: false, isIdentityVerified: false,
isRewardApproved: false, isRewardApproved: false,
revealVerification: true,
usdExchangeRate: 0,
verifyRequestStarted: false, verifyRequestStarted: false,
revealVerification: true,
firstRewardClaimed: false,
currentFilter: FILTER_AVAILABLE,
}; };
scrollView = null; scrollView = null;
@ -49,12 +48,6 @@ class RewardsPage extends React.PureComponent {
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Rewards'); NativeModules.Firebase.setCurrentScreen('Rewards');
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
fetchRewards(); fetchRewards();
this.setState({ this.setState({
@ -165,7 +158,6 @@ class RewardsPage extends React.PureComponent {
canClaim={!isNotEligible} canClaim={!isNotEligible}
reward={reward} reward={reward}
reward_type={reward.reward_type} reward_type={reward.reward_type}
usdExchangeRate={this.state.usdExchangeRate}
/> />
))} ))}
<CustomRewardCard canClaim={!isNotEligible} showVerification={this.showVerification} /> <CustomRewardCard canClaim={!isNotEligible} showVerification={this.showVerification} />
@ -200,28 +192,13 @@ class RewardsPage extends React.PureComponent {
}; };
render() { render() {
const { navigation, sdkReady } = this.props; const { user, navigation } = this.props;
const { currentFilter } = this.state; const { currentFilter } = this.state;
if (!sdkReady) {
return (
<View style={rewardStyle.container}>
<UriBar navigation={navigation} />
<EmptyStateView
message={__(
'The background service is still initializing. You can still explore and watch content during the initialization process.',
)}
/>
</View>
);
}
return ( return (
<View style={rewardStyle.container}> <View style={rewardStyle.container}>
<UriBar navigation={navigation} /> <UriBar navigation={navigation} />
{(!this.state.isEmailVerified || !this.state.isRewardApproved) && ( {(!this.state.isEmailVerified || !this.state.isRewardApproved) && <RewardEnrolment navigation={navigation} />}
<RewardEnrolment usdExchangeRate={this.state.usdExchangeRate} navigation={navigation} />
)}
{this.state.isEmailVerified && this.state.isRewardApproved && ( {this.state.isEmailVerified && this.state.isRewardApproved && (
<ScrollView <ScrollView

View file

@ -26,14 +26,10 @@ const select = state => ({
query: selectSearchValue(state), query: selectSearchValue(state),
resolvingUris: selectResolvingUris(state), resolvingUris: selectResolvingUris(state),
showNsfwContent: selectShowNsfw(state), showNsfwContent: selectShowNsfw(state),
uris: makeSelectSearchUris( uris: makeSelectSearchUris(makeSelectQueryWithOptions(null, Constants.DEFAULT_PAGE_SIZE)(state))(state),
makeSelectQueryWithOptions(null, { size: Constants.DEFAULT_PAGE_SIZE, isBackgroundSearch: false })(state), results: makeSelectResolvedSearchResults(makeSelectQueryWithOptions(null, Constants.DEFAULT_PAGE_SIZE)(state))(state),
)(state),
results: makeSelectResolvedSearchResults(
makeSelectQueryWithOptions(null, { size: Constants.DEFAULT_PAGE_SIZE, isBackgroundSearch: false })(state),
)(state),
lastPageReached: makeSelectResolvedSearchResultsLastPageReached( lastPageReached: makeSelectResolvedSearchResultsLastPageReached(
makeSelectQueryWithOptions(null, { size: Constants.DEFAULT_PAGE_SIZE, isBackgroundSearch: false })(state), makeSelectQueryWithOptions(null, Constants.DEFAULT_PAGE_SIZE)(state),
)(state), )(state),
}); });

View file

@ -11,7 +11,6 @@ const select = state => ({
backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state), backgroundPlayEnabled: makeSelectClientSetting(SETTINGS.BACKGROUND_PLAY_ENABLED)(state),
currentRoute: selectCurrentRoute(state), currentRoute: selectCurrentRoute(state),
drawerStack: selectDrawerStack(state), drawerStack: selectDrawerStack(state),
enableDht: makeSelectClientSetting(Constants.SETTING_DHT_ENABLED)(state),
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state), keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state), showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
@ -30,4 +29,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(SettingsPage); export default connect(
select,
perform
)(SettingsPage);

View file

@ -1,16 +1,6 @@
import React from 'react'; import React from 'react';
import { SETTINGS } from 'lbry-redux'; import { SETTINGS } from 'lbry-redux';
import { import { ActivityIndicator, Picker, Platform, Text, View, ScrollView, Switch, NativeModules } from 'react-native';
ActivityIndicator,
Picker,
Platform,
Text,
TextInput,
View,
ScrollView,
Switch,
NativeModules,
} from 'react-native';
import { navigateBack } from 'utils/helper'; import { navigateBack } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
@ -21,27 +11,16 @@ import settingsStyle from 'styles/settings';
const languageOptions = [ const languageOptions = [
{ code: 'default', name: 'Use device language' }, { code: 'default', name: 'Use device language' },
{ code: 'jv', name: 'Basa Jawa' },
{ code: 'da', name: 'Danish' },
{ code: 'nl', name: 'Dutch' },
{ code: 'en', name: 'English' }, { code: 'en', name: 'English' },
{ code: 'et', name: 'Estonian' },
{ code: 'fr', name: 'French' },
{ code: 'gu', name: 'Gujarati' }, { code: 'gu', name: 'Gujarati' },
{ code: 'hi', name: 'Hindi' }, { code: 'hi', name: 'Hindi' },
{ code: 'id', name: 'Indonesian' }, { code: 'id', name: 'Indonesian' },
{ code: 'it', name: 'Italian' }, { code: 'it', name: 'Italian' },
{ code: 'kn', name: 'Kannada' },
{ code: 'ms', name: 'Malay' }, { code: 'ms', name: 'Malay' },
{ code: 'mr', name: 'Marathi' }, { code: 'tr', name: 'Turkish' },
{ code: 'pl', name: 'Polish' }, { code: 'pl', name: 'Polish' },
{ code: 'pt', name: 'Portuguese' }, { code: 'pt', name: 'Portuguese' },
{ code: 'ro', name: 'Romanian' },
{ code: 'ru', name: 'Russian' },
{ code: 'sk', name: 'Slovak' },
{ code: 'es', name: 'Spanish' }, { code: 'es', name: 'Spanish' },
{ code: 'tr', name: 'Turkish' },
{ code: 'uk', name: 'Ukrainian' },
]; ];
class SettingsPage extends React.PureComponent { class SettingsPage extends React.PureComponent {
@ -161,7 +140,6 @@ class SettingsPage extends React.PureComponent {
render() { render() {
const { const {
backgroundPlayEnabled, backgroundPlayEnabled,
enableDht,
keepDaemonRunning, keepDaemonRunning,
receiveSubscriptionNotifications, receiveSubscriptionNotifications,
receiveRewardNotifications, receiveRewardNotifications,
@ -179,7 +157,6 @@ class SettingsPage extends React.PureComponent {
const actualReceiveRewardNotifications = this.getBooleanSetting(receiveRewardNotifications, true); const actualReceiveRewardNotifications = this.getBooleanSetting(receiveRewardNotifications, true);
const actualReceiveInterestsNotifications = this.getBooleanSetting(receiveInterestsNotifications, true); const actualReceiveInterestsNotifications = this.getBooleanSetting(receiveInterestsNotifications, true);
const actualReceiveCreatorNotifications = this.getBooleanSetting(receiveCreatorNotifications, true); const actualReceiveCreatorNotifications = this.getBooleanSetting(receiveCreatorNotifications, true);
const actualEnableDht = this.getBooleanSetting(enableDht, false);
return ( return (
<View style={settingsStyle.container}> <View style={settingsStyle.container}>
@ -317,7 +294,7 @@ class SettingsPage extends React.PureComponent {
</Text> </Text>
<Text style={settingsStyle.description}> <Text style={settingsStyle.description}>
{__( {__(
'Enable this option for quicker app launch and to keep the synchronisation with the blockchain up to date.', 'Enable this option for quicker app launch and to keep the synchronisation with the blockchain up to date.'
)} )}
</Text> </Text>
</View> </View>
@ -333,25 +310,6 @@ class SettingsPage extends React.PureComponent {
/> />
</View> </View>
</View> </View>
<View style={settingsStyle.row}>
<View style={settingsStyle.switchText}>
<Text style={settingsStyle.label}>{__('Participate in the data network')}</Text>
<Text style={settingsStyle.description}>
{__(
'Enable peer-to-peer functionality (this will take effect upon app and background service restart)',
)}
</Text>
</View>
<View style={settingsStyle.switchContainer}>
<Switch
value={actualEnableDht}
onValueChange={value => {
this.setNativeBooleanSetting(Constants.SETTING_DHT_ENABLED, value);
}}
/>
</View>
</View>
</ScrollView> </ScrollView>
</View> </View>
); );

View file

@ -1,9 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { SETTINGS, doUpdateBlockHeight, doPopulateSharedUserState, doToast } from 'lbry-redux'; import { SETTINGS, doBalanceSubscribe, doUpdateBlockHeight, doPopulateSharedUserState, doToast } from 'lbry-redux';
import { import {
doAuthenticate, doAuthenticate,
doClaimRewardType, doBlackListedOutpointsSubscribe,
doInstallNewWithParams, doFilteredOutpointsSubscribe,
doFetchMySubscriptions, doFetchMySubscriptions,
doFetchRewardedContent, doFetchRewardedContent,
doGetSync, doGetSync,
@ -26,10 +26,10 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
authenticate: (appVersion, os, firebaseToken, callInstall) => authenticate: (appVersion, os, firebaseToken) => dispatch(doAuthenticate(appVersion, os, firebaseToken)),
dispatch(doAuthenticate(appVersion, os, firebaseToken, true, null, callInstall)), balanceSubscribe: () => dispatch(doBalanceSubscribe()),
installNewWithParams: (appVersion, installationId, nodeId, lbrynetVersion, os, platform, firebaseToken) => blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
dispatch(doInstallNewWithParams(appVersion, installationId, nodeId, lbrynetVersion, os, platform, firebaseToken)), filteredOutpointsSubscribe: () => dispatch(doFilteredOutpointsSubscribe()),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()), fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
fetchSubscriptions: callback => dispatch(doFetchMySubscriptions(callback)), fetchSubscriptions: callback => dispatch(doFetchMySubscriptions(callback)),
getSync: (password, callback) => dispatch(doGetSync(password, callback)), getSync: (password, callback) => dispatch(doGetSync(password, callback)),
@ -42,4 +42,7 @@ const perform = dispatch => ({
verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)), verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)),
}); });
export default connect(select, perform)(SplashScreen); export default connect(
select,
perform,
)(SplashScreen);

View file

@ -23,12 +23,9 @@ class SplashScreen extends React.PureComponent {
}; };
state = { state = {
authWithoutSdk: false,
accountUnlockFailed: false, accountUnlockFailed: false,
appVersion: null,
daemonReady: false, daemonReady: false,
details: __('Starting up'), details: __('Starting up'),
firebaseToken: null,
message: __('Connecting'), message: __('Connecting'),
isRunning: false, isRunning: false,
isLagging: false, isLagging: false,
@ -37,57 +34,12 @@ class SplashScreen extends React.PureComponent {
headersDownloadProgress: 0, headersDownloadProgress: 0,
shouldAuthenticate: false, shouldAuthenticate: false,
subscriptionsFetched: false, subscriptionsFetched: false,
liteMode: false,
liteModeParams: {},
}; };
initLiteMode = () => {
NativeModules.UtilityModule.getLbrynetDirectory().then(path => {
NativeModules.UtilityModule.getPlatform().then(platform => {
RNFS.readFile(`${path}/install_id`, 'utf8')
.then(installIdContent => {
// node_id is actually optional (won't be present if dht is disabled)
// RNFS.readFile(`${path}/node_id`, 'utf8').then(nodeIdContent => {
// TODO: Load proper lbrynetVersion value
this.setState(
{
liteModeParams: {
installationId: installIdContent,
nodeId: null,
lbrynetVersion: '0.64.0',
platform,
},
},
() => this.updateStatus(),
);
// }).catch((err) => { console.log(err); console.log('node_id not found.'); this.lbryConnect() });
})
.catch(() => this.lbryConnect());
});
});
};
authenticateWithoutSdk() {
const { authenticate } = this.props;
NativeModules.VersionInfo.getAppVersion().then(appVersion => {
this.setState({ appVersion, shouldAuthenticate: true, authWithoutSdk: true });
NativeModules.Firebase.getMessagingToken()
.then(firebaseToken => {
this.setState({ firebaseToken }, () => authenticate(appVersion, Platform.OS, firebaseToken, false));
})
.catch(() => {
authenticate(appVersion, Platform.OS, null, false);
});
});
}
updateStatus() { updateStatus() {
const { liteMode } = this.state; Lbry.status().then(status => {
this._updateStatusCallback(status);
// authenticate immediately });
if (!NativeModules.UtilityModule.dhtEnabled) {
this.authenticateWithoutSdk();
}
} }
navigateToMain = () => { navigateToMain = () => {
@ -115,76 +67,31 @@ class SplashScreen extends React.PureComponent {
} }
} }
} }
// splash screen is done at this point, next page to be displayed will be user-interactable
NativeModules.Firebase.logLaunchTiming();
}; };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { getSync, installNewWithParams } = this.props; const { emailToVerify, getSync, setEmailToVerify, verifyUserEmail, verifyUserEmailFailure } = this.props;
const { const { daemonReady, shouldAuthenticate } = this.state;
daemonReady,
authWithoutSdk,
shouldAuthenticate,
liteMode,
liteModeParams,
appVersion,
firebaseToken,
} = this.state;
const { user } = nextProps; const { user } = nextProps;
if (liteMode && user && user.id) { if (daemonReady && shouldAuthenticate && user && user.id) {
this.navigateToLiteMode(); this.setState({ shouldAuthenticate: false }, () => {
} else if (shouldAuthenticate && user && user.id) { // user is authenticated, navigate to the main view
if (daemonReady || authWithoutSdk) { if (user.has_verified_email) {
this.setState({ shouldAuthenticate: false }, () => { NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
// call install new after successful authentication getSync(walletPassword, () => {
if (authWithoutSdk) { this.getUserSettings();
const { installationId, nodeId, lbrynetVersion, platform } = liteModeParams;
installNewWithParams(
appVersion,
installationId,
nodeId,
lbrynetVersion,
Platform.OS,
platform,
firebaseToken,
);
}
// user is authenticated, navigate to the main view
if (user.has_verified_email) {
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
getSync(walletPassword, () => {
this.getUserSettings();
});
}); });
});
this.navigateToMain();
return;
}
this.navigateToMain(); this.navigateToMain();
}); return;
} }
this.navigateToMain();
});
} }
} }
navigateToLiteMode = () => {
const { navigation } = this.props;
const { launchUrl } = this.state;
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName: Constants.DRAWER_ROUTE_LITE_FILE,
params: { uri: launchUrl },
}),
],
});
navigation.dispatch(resetAction);
};
getUserSettings = () => { getUserSettings = () => {
const { populateSharedUserState } = this.props; const { populateSharedUserState } = this.props;
@ -206,9 +113,22 @@ class SplashScreen extends React.PureComponent {
}; };
finishSplashScreen = () => { finishSplashScreen = () => {
const { authenticate, getSync, user } = this.props; const {
authenticate,
balanceSubscribe,
blacklistedOutpointsSubscribe,
filteredOutpointsSubscribe,
getSync,
updateBlockHeight,
user,
} = this.props;
// Lbry.resolve({ urls: 'lbry://one' }).then(() => {
// Leave the splash screen // Leave the splash screen
balanceSubscribe();
blacklistedOutpointsSubscribe();
filteredOutpointsSubscribe();
if (user && user.id && user.has_verified_email) { if (user && user.id && user.has_verified_email) {
// user already authenticated // user already authenticated
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => { NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(walletPassword => {
@ -222,20 +142,37 @@ class SplashScreen extends React.PureComponent {
this.setState({ shouldAuthenticate: true }, () => { this.setState({ shouldAuthenticate: true }, () => {
NativeModules.Firebase.getMessagingToken() NativeModules.Firebase.getMessagingToken()
.then(firebaseToken => { .then(firebaseToken => {
authenticate(appVersion, Platform.OS, firebaseToken, true); authenticate(appVersion, Platform.OS, firebaseToken);
}) })
.catch(() => authenticate(appVersion, Platform.OS, null, true)); .catch(() => authenticate(appVersion, Platform.OS));
}); });
}); });
} }
// });
}; };
handleAccountUnlockFailed() { handleAccountUnlockFailed() {
this.setState({ accountUnlockFailed: true }); this.setState({ accountUnlockFailed: true });
} }
handleSdkReady = () => { _updateStatusCallback(status) {
this.setState({ daemonReady: true }, () => { const { fetchSubscriptions, getSync, setClientSetting } = this.props;
const startupStatus = status.startup_status;
const walletStatus = status.wallet;
// At the minimum, wallet should be started and blocks_behind equal to 0 before calling resolve
const hasStarted = startupStatus.stream_manager && startupStatus.wallet && status.wallet.blocks_behind <= 0;
if (hasStarted) {
// Wait until we are able to resolve a name before declaring
// that we are done.
// TODO: This is a hack, and the logic should live in the daemon
// to give us a better sense of when we are actually started
this.setState({
daemonReady: true,
isLagging: false,
isRunning: true,
});
Lbry.wallet_status().then(secureWalletStatus => { Lbry.wallet_status().then(secureWalletStatus => {
// For now, automatically unlock the wallet if a password is set so that downloads work // For now, automatically unlock the wallet if a password is set so that downloads work
NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password => { NativeModules.UtilityModule.getSecureValue(Constants.KEY_WALLET_PASSWORD).then(password => {
@ -266,12 +203,9 @@ class SplashScreen extends React.PureComponent {
} }
}); });
}); });
});
};
handleSdkStatusResponse = evt => { return;
const { status } = evt; }
const walletStatus = status.wallet;
const headerSyncProgress = walletStatus ? walletStatus.headers_synchronization_progress : null; const headerSyncProgress = walletStatus ? walletStatus.headers_synchronization_progress : null;
if (headerSyncProgress && headerSyncProgress < 100) { if (headerSyncProgress && headerSyncProgress < 100) {
@ -306,45 +240,49 @@ class SplashScreen extends React.PureComponent {
details: __('Initializing LBRY service'), details: __('Initializing LBRY service'),
}); });
} }
};
setTimeout(() => {
this.updateStatus();
}, 1000);
}
componentWillMount() { componentWillMount() {
DeviceEventEmitter.addListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch); DeviceEventEmitter.addListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch);
DeviceEventEmitter.addListener('onSdkReady', this.handleSdkReady);
DeviceEventEmitter.addListener('onSdkStatusResponse', this.handleSdkStatusResponse);
} }
componentWillUnmount() { componentWillUnmount() {
DeviceEventEmitter.removeListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch); DeviceEventEmitter.removeListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch);
DeviceEventEmitter.removeListener('onSdkReady', this.handleSdkReady);
DeviceEventEmitter.removeListener('onSdkStatusResponse', this.handleSdkStatusResponse);
} }
componentDidMount() { componentDidMount() {
NativeModules.Firebase.track('app_launch', null); NativeModules.Firebase.track('app_launch', null);
NativeModules.Firebase.setCurrentScreen('Splash'); NativeModules.Firebase.setCurrentScreen('Splash');
NativeModules.UtilityModule.checkSdkReady();
const { navigation } = this.props;
const { resetUrl } = navigation.state.params;
const isResetUrlSet = !!resetUrl;
this.props.fetchRewardedContent(); this.props.fetchRewardedContent();
Linking.getInitialURL().then(url => { Linking.getInitialURL().then(url => {
let liteMode;
if (url) { if (url) {
liteMode = !isResetUrlSet && url.indexOf('liteMode=1') > -1; this.setState({ launchUrl: url });
this.setState({ launchUrl: resetUrl || url, liteMode });
} }
NativeModules.UtilityModule.getNotificationLaunchTarget().then(target => { NativeModules.UtilityModule.getNotificationLaunchTarget().then(target => {
if (target) { if (target) {
liteMode = !isResetUrlSet && target.indexOf('liteMode=1') > -1; this.setState({ launchUrl: target });
this.setState({ launchUrl: resetUrl || target, liteMode });
} }
// Only connect after checking initial launch url / notification launch target // Only connect after checking initial launch url / notification launch target
this.initLiteMode(); Lbry.connect()
.then(() => {
this.updateStatus();
})
.catch(e => {
this.setState({
isLagging: true,
message: __('Connection Failure'),
details: __(
'We could not establish a connection to the SDK. Your data connection may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.',
),
});
});
}); });
}); });
@ -359,26 +297,6 @@ class SplashScreen extends React.PureComponent {
}); });
} }
lbryConnect = () => {
if (NativeModules.UtilityModule.dhtEnabled) {
Lbry.connect()
.then(() => {
this.updateStatus();
})
.catch(e => {
this.setState({
isLagging: true,
message: __('Connection Failure'),
details: __(
'We could not establish a connection to the SDK. Your data connection may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.',
),
});
});
} else {
this.updateStatus(); // skip lbry.connect for now (unless dht flag is enabled)
}
};
handleContinueAnywayPressed = () => { handleContinueAnywayPressed = () => {
this.setState( this.setState(
{ {

View file

@ -7,18 +7,16 @@ import {
selectSubscriptionClaims, selectSubscriptionClaims,
selectSubscriptions, selectSubscriptions,
selectIsFetchingSubscriptions, selectIsFetchingSubscriptions,
selectIsFetchingSuggested,
selectSuggestedChannels, selectSuggestedChannels,
selectUnreadSubscriptions, selectUnreadSubscriptions,
selectViewMode, selectViewMode,
selectFirstRunCompleted, selectFirstRunCompleted,
selectShowSuggestedSubs, selectShowSuggestedSubs,
selectUnclaimedRewardValue,
selectUser,
} from 'lbryinc'; } from 'lbryinc';
import { doToast, selectFetchingClaimSearch } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetClientSetting, doSetTimeItem } from 'redux/actions/settings'; import { doSetClientSetting, doSetTimeItem } from 'redux/actions/settings';
import { makeSelectClientSetting, selectSdkReady, selectTimeItem } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectTimeItem } from 'redux/selectors/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import SubscriptionsPage from './view'; import SubscriptionsPage from './view';
@ -26,7 +24,7 @@ import SubscriptionsPage from './view';
const select = state => ({ const select = state => ({
currentRoute: selectCurrentRoute(state), currentRoute: selectCurrentRoute(state),
loading: selectIsFetchingSubscriptions(state), loading: selectIsFetchingSubscriptions(state),
loadingSuggested: selectFetchingClaimSearch(state), loadingSuggested: selectIsFetchingSuggested(state),
subscribedChannels: selectSubscriptions(state), subscribedChannels: selectSubscriptions(state),
suggestedChannels: selectSuggestedChannels(state), suggestedChannels: selectSuggestedChannels(state),
subscriptionsViewMode: makeSelectClientSetting(Constants.SETTING_SUBSCRIPTIONS_VIEW_MODE)(state), subscriptionsViewMode: makeSelectClientSetting(Constants.SETTING_SUBSCRIPTIONS_VIEW_MODE)(state),
@ -34,12 +32,8 @@ const select = state => ({
unreadSubscriptions: selectUnreadSubscriptions(state), unreadSubscriptions: selectUnreadSubscriptions(state),
viewMode: selectViewMode(state), viewMode: selectViewMode(state),
firstRunCompleted: selectFirstRunCompleted(state), firstRunCompleted: selectFirstRunCompleted(state),
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
showSuggestedSubs: selectShowSuggestedSubs(state), showSuggestedSubs: selectShowSuggestedSubs(state),
timeItem: selectTimeItem(state), timeItem: selectTimeItem(state),
sdkReady: selectSdkReady(state),
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
user: selectUser(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
@ -47,11 +41,13 @@ const perform = dispatch => ({
doFetchMySubscriptions: () => dispatch(doFetchMySubscriptions()), doFetchMySubscriptions: () => dispatch(doFetchMySubscriptions()),
doFetchRecommendedSubscriptions: () => dispatch(doFetchRecommendedSubscriptions()), doFetchRecommendedSubscriptions: () => dispatch(doFetchRecommendedSubscriptions()),
doSetViewMode: viewMode => dispatch(doSetViewMode(viewMode)), doSetViewMode: viewMode => dispatch(doSetViewMode(viewMode)),
notify: data => dispatch(doToast(data)),
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SUBSCRIPTIONS)),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
setTimeItem: item => dispatch(doSetTimeItem(item)), setTimeItem: item => dispatch(doSetTimeItem(item)),
}); });
export default connect(select, perform)(SubscriptionsPage); export default connect(
select,
perform
)(SubscriptionsPage);

View file

@ -11,7 +11,7 @@ import {
View, View,
} from 'react-native'; } from 'react-native';
import { buildURI, parseURI } from 'lbry-redux'; import { buildURI, parseURI } from 'lbry-redux';
import { formatUsd, getOrderBy } from 'utils/helper'; import { getOrderBy } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import moment from 'moment'; import moment from 'moment';
import Button from 'component/button'; import Button from 'component/button';
@ -28,24 +28,17 @@ import ModalPicker from 'component/modalPicker';
import ModalSuggestedSubscriptions from 'component/modalSuggestedSubscriptions'; import ModalSuggestedSubscriptions from 'component/modalSuggestedSubscriptions';
import SubscribedChannelList from 'component/subscribedChannelList'; import SubscribedChannelList from 'component/subscribedChannelList';
import SuggestedSubscriptions from 'component/suggestedSubscriptions'; import SuggestedSubscriptions from 'component/suggestedSubscriptions';
import SuggestedSubscriptionsGrid from 'component/suggestedSubscriptionsGrid';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
import SdkLoadingStatus from 'component/sdkLoadingStatus';
import Snackbar from 'react-native-snackbar';
import { Lbryio } from 'lbryinc';
class SubscriptionsPage extends React.PureComponent { class SubscriptionsPage extends React.PureComponent {
state = { state = {
currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new
filteredChannels: [],
orderBy: ['release_time'],
showRewardsNag: true,
showingSuggestedSubs: false, showingSuggestedSubs: false,
showSortPicker: false, showSortPicker: false,
showTimePicker: false, showTimePicker: false,
showModalSuggestedSubs: false, showModalSuggestedSubs: false,
usdExchangeRate: 0, orderBy: ['release_time'],
userEmailVerified: false, filteredChannels: [],
currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new
}; };
didFocusListener; didFocusListener;
@ -62,26 +55,21 @@ class SubscriptionsPage extends React.PureComponent {
} }
onComponentFocused = () => { onComponentFocused = () => {
const { currentRoute, doFetchMySubscriptions, pushDrawerStack, sdkReady, setPlayerVisible, user } = this.props; const {
doFetchMySubscriptions,
doFetchRecommendedSubscriptions,
doSetViewMode,
pushDrawerStack,
setPlayerVisible,
subscriptionsViewMode,
} = this.props;
if (currentRoute === Constants.DRAWER_ROUTE_SUBSCRIPTIONS) { pushDrawerStack();
pushDrawerStack();
}
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Subscriptions'); NativeModules.Firebase.setCurrentScreen('Subscriptions');
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD }, () => {
if (sdkReady && parseFloat(this.state.usdExchangeRate) > 0 && user && !user.is_reward_approved) {
this.showRewardsAvailable();
}
});
}
});
this.setState({ userEmailVerified: user && user.has_verified_email });
doFetchMySubscriptions(); doFetchMySubscriptions();
doFetchRecommendedSubscriptions();
}; };
componentDidMount() { componentDidMount() {
@ -89,69 +77,19 @@ class SubscriptionsPage extends React.PureComponent {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { currentRoute, user, sdkReady } = nextProps; const { currentRoute } = nextProps;
const { currentRoute: prevRoute, doFetchMySubscriptions } = this.props; const { currentRoute: prevRoute } = this.props;
if (Constants.DRAWER_ROUTE_SUBSCRIPTIONS === currentRoute && currentRoute !== prevRoute) { if (Constants.DRAWER_ROUTE_SUBSCRIPTIONS === currentRoute && currentRoute !== prevRoute) {
this.onComponentFocused(); this.onComponentFocused();
} }
if (user && user.has_verified_email && !this.state.userEmailVerified) {
// user just signed in
this.setState({ showingSuggestedSubs: false, userEmailVerified: true }, () => {
doFetchMySubscriptions();
});
}
if (
sdkReady &&
parseFloat(this.state.usdExchangeRate) > 0 &&
this.state.showRewardsNag &&
user &&
!user.is_reward_approved
) {
this.showRewardsAvailable();
}
this.unsubscribeShortChannelUrls(); this.unsubscribeShortChannelUrls();
} }
showRewardsAvailable = () => {
const { navigation, unclaimedRewardAmount, rewardsNotInterested } = this.props;
if (rewardsNotInterested) {
this.setState({ showRewardsNag: false });
return;
}
this.setState({ showRewardsNag: false }, () => {
Snackbar.show({
title: __('Did you know that you can earn free credits worth up to %amount%?', {
amount: formatUsd(parseFloat(this.state.usdExchangeRate) * parseFloat(unclaimedRewardAmount)),
}),
duration: Snackbar.LENGTH_LONG,
action: {
title: __('SHOW ME'),
color: Colors.LbryGreen,
onPress: () => {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_REWARDS });
},
},
});
});
};
handleSortByItemSelected = item => { handleSortByItemSelected = item => {
this.setState({ currentSortByItem: item, orderBy: getOrderBy(item), showSortPicker: false }); this.setState({ currentSortByItem: item, orderBy: getOrderBy(item), showSortPicker: false });
}; };
shouldComponentUpdate(nextProps, nextState) {
const { showModalSuggestedSubs: prevShowModalSuggestedSubs } = this.state;
const { showModalSuggestedSubs } = this.state;
if (prevShowModalSuggestedSubs && showModalSuggestedSubs) {
return false;
}
return true;
}
handleTimeItemSelected = item => { handleTimeItemSelected = item => {
const { setTimeItem } = this.props; const { setTimeItem } = this.props;
setTimeItem(item); setTimeItem(item);
@ -187,7 +125,20 @@ class SubscriptionsPage extends React.PureComponent {
}; };
render() { render() {
const { subscribedChannels, loading, loadingSuggested, sdkReady, timeItem, navigation, notify } = this.props; const {
suggestedChannels,
subscribedChannels,
allSubscriptions,
doCompleteFirstRun,
doShowSuggestedSubs,
loading,
loadingSuggested,
firstRunCompleted,
showSuggestedSubs,
timeItem,
unreadSubscriptions,
navigation,
} = this.props;
const { currentSortByItem, filteredChannels, showModalSuggestedSubs, showSortPicker, showTimePicker } = this.state; const { currentSortByItem, filteredChannels, showModalSuggestedSubs, showSortPicker, showTimePicker } = this.state;
const numberOfSubscriptions = subscribedChannels ? subscribedChannels.length : 0; const numberOfSubscriptions = subscribedChannels ? subscribedChannels.length : 0;
@ -213,11 +164,7 @@ class SubscriptionsPage extends React.PureComponent {
<View style={subscriptionsStyle.container}> <View style={subscriptionsStyle.container}>
<UriBar navigation={navigation} belowOverlay={this.state.showSortPicker} /> <UriBar navigation={navigation} belowOverlay={this.state.showSortPicker} />
<View style={subscriptionsStyle.titleRow}> <View style={subscriptionsStyle.titleRow}>
<Text style={subscriptionsStyle.pageTitle}> <Text style={subscriptionsStyle.pageTitle}>{__('Channels you follow')}</Text>
{hasSubscriptions && !this.state.showingSuggestedSubs
? __('Channels you follow')
: __('Find Channels to follow')}
</Text>
</View> </View>
{!this.state.showingSuggestedSubs && hasSubscriptions && ( {!this.state.showingSuggestedSubs && hasSubscriptions && (
<View style={subscriptionsStyle.pickerRow}> <View style={subscriptionsStyle.pickerRow}>
@ -243,7 +190,7 @@ class SubscriptionsPage extends React.PureComponent {
<Link <Link
style={subscriptionsStyle.suggestedLink} style={subscriptionsStyle.suggestedLink}
text={__('Discover')} text={__('Suggested')}
onPress={() => this.setState({ showModalSuggestedSubs: true })} onPress={() => this.setState({ showModalSuggestedSubs: true })}
/> />
</View> </View>
@ -273,40 +220,39 @@ class SubscriptionsPage extends React.PureComponent {
{this.state.showingSuggestedSubs && ( {this.state.showingSuggestedSubs && (
<View style={subscriptionsStyle.suggestedSubsContainer}> <View style={subscriptionsStyle.suggestedSubsContainer}>
<View style={subscriptionsStyle.infoArea}> {!hasSubscriptions && (
<Text style={subscriptionsStyle.infoText}> <View style={subscriptionsStyle.infoArea}>
{__( <Text style={subscriptionsStyle.infoText}>
'LBRY works better if you follow at least 5 creators you like. Sign in to show creators you follow if you already have an account.', {__('You are not subscribed to any channels at the moment.')}
)} </Text>
</Text> </View>
</View> )}
<View style={subscriptionsStyle.mainSuggested}> {hasSubscriptions && (
<SuggestedSubscriptionsGrid navigation={navigation} /> <View style={subscriptionsStyle.infoArea}>
</View> <Text style={subscriptionsStyle.infoText}>
You are currently subscribed to {numberOfSubscriptions} channel{numberOfSubscriptions > 1 ? 's' : ''}.
<Button </Text>
style={subscriptionsStyle.suggestedDoneButton} <Button
text={ style={subscriptionsStyle.button}
numberOfSubscriptions < 5 text={__('View my subscriptions')}
? __('%remaining% more...', { remaining: 5 - numberOfSubscriptions }) onPress={() => this.setState({ showingSuggestedSubs: false })}
: __('Done') />
} </View>
onPress={() => { )}
if (!hasSubscriptions) {
notify({ message: __('Tap on any channel to follow') });
} else {
this.setState({ showingSuggestedSubs: false });
}
}}
/>
{loadingSuggested && ( {loadingSuggested && (
<ActivityIndicator size="small" color={Colors.White} style={subscriptionsStyle.suggestedLoading} /> <View style={subscriptionsStyle.centered}>
<ActivityIndicator size="large" colors={Colors.NextLbryGreen} style={subscriptionsStyle.loading} />
</View>
)} )}
{!loadingSuggested && <SuggestedSubscriptions navigation={navigation} />}
</View> </View>
)} )}
{!showSortPicker && !showTimePicker && !showModalSuggestedSubs && (
<FloatingWalletBalance navigation={navigation} />
)}
{showSortPicker && ( {showSortPicker && (
<ModalPicker <ModalPicker
title={__('Sort content by')} title={__('Sort content by')}
@ -332,8 +278,6 @@ class SubscriptionsPage extends React.PureComponent {
onDonePress={() => this.setState({ showModalSuggestedSubs: false })} onDonePress={() => this.setState({ showModalSuggestedSubs: false })}
/> />
)} )}
{!sdkReady && <SdkLoadingStatus />}
</View> </View>
); );
} }

View file

@ -3,12 +3,11 @@ import { selectFollowedTags, doToggleTagFollow } from 'lbry-redux';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings'; import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import { selectSdkReady, selectSortByItem, selectTimeItem } from 'redux/selectors/settings'; import { selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
import TagPage from './view'; import TagPage from './view';
const select = state => ({ const select = state => ({
currentRoute: selectCurrentRoute(state), currentRoute: selectCurrentRoute(state),
sdkReady: selectSdkReady(state),
sortByItem: selectSortByItem(state), sortByItem: selectSortByItem(state),
timeItem: selectTimeItem(state), timeItem: selectTimeItem(state),
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
@ -22,4 +21,7 @@ const perform = dispatch => ({
toggleTagFollow: tag => dispatch(doToggleTagFollow(tag)), toggleTagFollow: tag => dispatch(doToggleTagFollow(tag)),
}); });
export default connect(select, perform)(TagPage); export default connect(
select,
perform
)(TagPage);

View file

@ -14,7 +14,6 @@ import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import FloatingWalletBalance from 'component/floatingWalletBalance'; import FloatingWalletBalance from 'component/floatingWalletBalance';
import Link from 'component/link'; import Link from 'component/link';
import ModalPicker from 'component/modalPicker'; import ModalPicker from 'component/modalPicker';
import SdkLoadingStatus from 'component/sdkLoadingStatus';
import UriBar from 'component/uriBar'; import UriBar from 'component/uriBar';
class TagPage extends React.PureComponent { class TagPage extends React.PureComponent {
@ -128,7 +127,7 @@ class TagPage extends React.PureComponent {
}; };
render() { render() {
const { navigation, sdkReady, sortByItem, timeItem } = this.props; const { navigation, sortByItem, timeItem } = this.props;
const { tag, showSortPicker, showTimePicker } = this.state; const { tag, showSortPicker, showTimePicker } = this.state;
return ( return (
@ -145,7 +144,7 @@ class TagPage extends React.PureComponent {
orientation={Constants.ORIENTATION_VERTICAL} orientation={Constants.ORIENTATION_VERTICAL}
/> />
)} )}
{sdkReady && !showSortPicker && !showTimePicker && <FloatingWalletBalance navigation={navigation} />} {!showSortPicker && !showTimePicker && <FloatingWalletBalance navigation={navigation} />}
{showSortPicker && ( {showSortPicker && (
<ModalPicker <ModalPicker
title={__('Sort content by')} title={__('Sort content by')}
@ -164,7 +163,6 @@ class TagPage extends React.PureComponent {
items={Constants.CLAIM_SEARCH_TIME_ITEMS} items={Constants.CLAIM_SEARCH_TIME_ITEMS}
/> />
)} )}
{!sdkReady && <SdkLoadingStatus />}
</View> </View>
); );
} }

View file

@ -1,6 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { makeSelectClientSetting, selectSdkReady } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { selectCurrentRoute } from 'redux/selectors/drawer'; import { selectCurrentRoute } from 'redux/selectors/drawer';
import { selectBalance } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
@ -15,7 +15,6 @@ const select = state => ({
deviceWalletSynced: makeSelectClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED)(state), deviceWalletSynced: makeSelectClientSetting(Constants.SETTING_DEVICE_WALLET_SYNCED)(state),
hasSyncedWallet: selectHasSyncedWallet(state), hasSyncedWallet: selectHasSyncedWallet(state),
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state), rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
sdkReady: selectSdkReady(state),
understandsRisks: makeSelectClientSetting(Constants.SETTING_ALPHA_UNDERSTANDS_RISKS)(state), understandsRisks: makeSelectClientSetting(Constants.SETTING_ALPHA_UNDERSTANDS_RISKS)(state),
user: selectUser(state), user: selectUser(state),
}); });
@ -28,4 +27,7 @@ const perform = dispatch => ({
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
}); });
export default connect(select, perform)(WalletPage); export default connect(
select,
perform
)(WalletPage);

Some files were not shown because too many files have changed in this diff Show more