From 9bc5a1538aa1d11c7b8512b998f1c73c3a30df89 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 30 Oct 2019 10:35:43 +0100 Subject: [PATCH 1/8] RC (#72) * show tag search result * fix suggested subscriptions. reduce number of search results. * run claim search for tag result --- .../suggestedSubscriptionItem/view.js | 4 +- src/page/search/index.js | 6 +- src/page/search/view.js | 65 +++++++++++++++++-- src/styles/search.js | 20 ++++-- 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/component/suggestedSubscriptionItem/view.js b/src/component/suggestedSubscriptionItem/view.js index aa22439..35b60a1 100644 --- a/src/component/suggestedSubscriptionItem/view.js +++ b/src/component/suggestedSubscriptionItem/view.js @@ -72,7 +72,9 @@ class SuggestedSubscriptionItem extends React.PureComponent { )} - + {claim && ( + + )} ); } diff --git a/src/page/search/index.js b/src/page/search/index.js index b86cc92..dc39f39 100644 --- a/src/page/search/index.js +++ b/src/page/search/index.js @@ -1,8 +1,10 @@ import { connect } from 'react-redux'; import { + doClaimSearch, doSearch, doUpdateSearchQuery, makeSelectSearchUris, + selectClaimSearchByQuery, selectIsSearching, selectSearchValue, makeSelectQueryWithOptions, @@ -13,9 +15,10 @@ import { selectCurrentRoute } from 'redux/selectors/drawer'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import SearchPage from './view'; -const numSearchResults = 50; +const numSearchResults = 25; const select = state => ({ + claimSearchByQuery: selectClaimSearchByQuery(state), currentRoute: selectCurrentRoute(state), isSearching: selectIsSearching(state), query: selectSearchValue(state), @@ -25,6 +28,7 @@ const select = state => ({ const perform = dispatch => ({ search: query => dispatch(doSearch(query, numSearchResults)), + claimSearch: options => dispatch(doClaimSearch(options)), updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SEARCH)), setPlayerVisible: () => dispatch(doSetPlayerVisible(false)), diff --git a/src/page/search/view.js b/src/page/search/view.js index d6580c0..1f5a8f4 100644 --- a/src/page/search/view.js +++ b/src/page/search/view.js @@ -1,6 +1,15 @@ import React from 'react'; -import { Lbry, parseURI, normalizeURI, isURIValid } from 'lbry-redux'; -import { ActivityIndicator, Button, FlatList, NativeModules, Text, TextInput, View } from 'react-native'; +import { Lbry, createNormalizedClaimSearchKey, parseURI, normalizeURI, isURIValid } from 'lbry-redux'; +import { + ActivityIndicator, + Button, + FlatList, + NativeModules, + Text, + TextInput, + TouchableOpacity, + View, +} from 'react-native'; import { navigateToUri } from 'utils/helper'; import Colors from 'styles/colors'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api @@ -14,6 +23,9 @@ class SearchPage extends React.PureComponent { state = { currentQuery: null, currentUri: null, + showTagResult: false, + claimSearchRun: false, + claimSearchOptions: null, }; static navigationOptions = { @@ -43,6 +55,9 @@ class SearchPage extends React.PureComponent { this.setState({ currentQuery: searchQuery, currentUri: isURIValid(searchQuery) ? normalizeURI(searchQuery) : null, + claimSearchOptions: null, + claimSearchRun: false, + showTagResult: false, }); search(searchQuery); } @@ -80,7 +95,12 @@ class SearchPage extends React.PureComponent { handleSearchSubmitted = keywords => { const { search } = this.props; - this.setState({ currentUri: isURIValid(keywords) ? normalizeURI(keywords) : null }); + this.setState({ + currentUri: isURIValid(keywords) ? normalizeURI(keywords) : null, + claimSearchOptions: null, + claimSearchRun: false, + showTagResult: false, + }); search(keywords); }; @@ -96,15 +116,45 @@ class SearchPage extends React.PureComponent { ); }; - listHeaderComponent = () => { - const { navigation } = this.props; + listHeaderComponent = showTagResult => { + const { navigation, claimSearch, claimSearchByQuery } = this.props; const { currentUri } = this.state; + const query = this.getSearchQuery(); + + const canBeTag = query && query.trim().length > 0 && isURIValid(query); + if (canBeTag && !this.state.claimSearchRun) { + const options = { + any_tags: [query], + page: 1, + no_totals: true, + }; + this.setState({ claimSearchOptions: options, claimSearchRun: true }, () => claimSearch(options)); + } + + if (this.state.claimSearchRun && this.state.claimSearchOptions) { + const claimSearchKey = createNormalizedClaimSearchKey(this.state.claimSearchOptions); + const claimSearchUris = claimSearchByQuery[claimSearchKey]; + this.setState({ showTagResult: claimSearchUris && claimSearchUris.length > 0 }); + } return ( - + + + {showTagResult && ( + this.handleTagResultPressed(query)}> + #{query} + Explore content for this tag + + )} + ); }; + handleTagResultPressed = tag => { + const { navigation } = this.props; + navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: `tagPage`, params: { tag } }); + }; + render() { const { isSearching, navigation, query, uris, urisByQuery } = this.props; @@ -119,6 +169,7 @@ class SearchPage extends React.PureComponent { )} ( )} diff --git a/src/styles/search.js b/src/styles/search.js index df62e8c..559d0a1 100644 --- a/src/styles/search.js +++ b/src/styles/search.js @@ -35,12 +35,24 @@ const searchStyle = StyleSheet.create({ flex: 1, flexDirection: 'row', justifyContent: 'space-between', - paddingTop: 8, - paddingBottom: 8, - paddingLeft: 8, - paddingRight: 8, + padding: 8, backgroundColor: Colors.Black, }, + tagResultItem: { + flex: 1, + padding: 16, + backgroundColor: Colors.DarkerGrey, + }, + tagResultTitle: { + fontFamily: 'Inter-UI-SemiBold', + fontSize: 24, + color: Colors.White, + }, + tagResultDescription: { + fontFamily: 'Inter-UI-Regular', + fontSize: 14, + color: Colors.VeryLightGrey, + }, searchInput: { width: '100%', height: '100%', From f714310681fa430aa84a4121ccca322bd2d6fd8e Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 30 Oct 2019 13:02:33 +0100 Subject: [PATCH 2/8] normalise tag name from search result --- src/page/search/view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/page/search/view.js b/src/page/search/view.js index 1f5a8f4..f1260d5 100644 --- a/src/page/search/view.js +++ b/src/page/search/view.js @@ -142,7 +142,7 @@ class SearchPage extends React.PureComponent { {showTagResult && ( this.handleTagResultPressed(query)}> - #{query} + #{query.toLowerCase()} Explore content for this tag )} @@ -152,7 +152,7 @@ class SearchPage extends React.PureComponent { handleTagResultPressed = tag => { const { navigation } = this.props; - navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: `tagPage`, params: { tag } }); + navigation.navigate({ routeName: Constants.DRAWER_ROUTE_TAG, key: `tagPage`, params: { tag: tag.toLowerCase() } }); }; render() { From 072ad25146ed840084562d3ef12a06b3fa926128 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Thu, 31 Oct 2019 07:52:57 +0100 Subject: [PATCH 3/8] fix for launch urls and notification target urls --- src/component/AppNavigator.js | 10 ++++++- src/page/splash/view.js | 55 +++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/component/AppNavigator.js b/src/component/AppNavigator.js index 812f89b..e335cba 100644 --- a/src/component/AppNavigator.js +++ b/src/component/AppNavigator.js @@ -27,7 +27,15 @@ import { createNavigationReducer, } from 'react-navigation-redux-helpers'; import { connect } from 'react-redux'; -import { AppState, BackHandler, Linking, NativeModules, TextInput, ToastAndroid } from 'react-native'; +import { + AppState, + BackHandler, + DeviceEventEmitter, + Linking, + NativeModules, + TextInput, + ToastAndroid, +} from 'react-native'; import { selectDrawerStack } from 'redux/selectors/drawer'; import { SETTINGS, doDismissToast, doPopulateSharedUserState, doPreferenceGet, doToast, selectToast } from 'lbry-redux'; import { diff --git a/src/page/splash/view.js b/src/page/splash/view.js index 4e1eddb..cc5a1fb 100644 --- a/src/page/splash/view.js +++ b/src/page/splash/view.js @@ -1,7 +1,7 @@ import React from 'react'; import { Lbry, doPreferenceGet } from 'lbry-redux'; import { Lbryio } from 'lbryinc'; -import { ActivityIndicator, Linking, NativeModules, Platform, Text, View } from 'react-native'; +import { ActivityIndicator, DeviceEventEmitter, Linking, NativeModules, Platform, Text, View } from 'react-native'; import { NavigationActions, StackActions } from 'react-navigation'; import { decode as atob } from 'base-64'; import { navigateToUri, transformUrl } from 'utils/helper'; @@ -52,7 +52,10 @@ class SplashScreen extends React.PureComponent { }); navigation.dispatch(resetAction); - const launchUrl = navigation.state.params ? navigation.state.params.launchUrl : this.state.launchUrl; + const launchUrl = + navigation.state.params && navigation.state.params.launchUrl + ? navigation.state.params.launchUrl + : this.state.launchUrl; if (launchUrl) { if (launchUrl.startsWith('lbry://?verify=')) { let verification = {}; @@ -118,6 +121,12 @@ class SplashScreen extends React.PureComponent { ); }; + onNotificationTargetLaunch = evt => { + if (evt.url && evt.url.startsWith('lbry://')) { + this.setState({ launchUrl: evt.url }); + } + }; + finishSplashScreen = () => { const { authenticate, @@ -250,15 +259,44 @@ class SplashScreen extends React.PureComponent { }, 1000); } + componentWillMount() { + DeviceEventEmitter.addListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch); + } + + componentWillUnmount() { + DeviceEventEmitter.removeListener('onNotificationTargetLaunch', this.onNotificationTargetLaunch); + } + componentDidMount() { NativeModules.Firebase.track('app_launch', null); NativeModules.Firebase.setCurrentScreen('Splash'); this.props.fetchRewardedContent(); Linking.getInitialURL().then(url => { + console.log('checking initial url=' + url); if (url) { this.setState({ launchUrl: url }); } + + NativeModules.UtilityModule.getNotificationLaunchTarget().then(target => { + if (target) { + this.setState({ launchUrl: target }); + } + + // Only connect after checking initial launch url / notification launch target + Lbry.connect() + .then(() => { + this.updateStatus(); + }) + .catch(e => { + this.setState({ + isLagging: true, + message: 'Connection Failure', + details: + 'We could not establish a connection to the daemon. Your data connection may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.', + }); + }); + }); }); // Start measuring the first launch time from the splash screen @@ -270,19 +308,6 @@ class SplashScreen extends React.PureComponent { AsyncStorage.setItem('firstLaunchTime', String(moment().unix())); } }); - - Lbry.connect() - .then(() => { - this.updateStatus(); - }) - .catch(e => { - this.setState({ - isLagging: true, - message: 'Connection Failure', - details: - 'We could not establish a connection to the daemon. Your data connection may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.', - }); - }); } handleContinueAnywayPressed = () => { From 943c5654c1cf7d9246964a3bc8826cffd2ae92f4 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Thu, 31 Oct 2019 07:54:42 +0100 Subject: [PATCH 4/8] cleanup console.log --- src/page/splash/view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/page/splash/view.js b/src/page/splash/view.js index cc5a1fb..4aa5615 100644 --- a/src/page/splash/view.js +++ b/src/page/splash/view.js @@ -273,7 +273,6 @@ class SplashScreen extends React.PureComponent { this.props.fetchRewardedContent(); Linking.getInitialURL().then(url => { - console.log('checking initial url=' + url); if (url) { this.setState({ launchUrl: url }); } From 5915919560f641d16da26b9dc06bd1a1f122585c Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Thu, 31 Oct 2019 17:34:32 +0100 Subject: [PATCH 5/8] hide notification settings --- src/page/settings/view.js | 90 ++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/page/settings/view.js b/src/page/settings/view.js index ffeb6fe..2b17b86 100644 --- a/src/page/settings/view.js +++ b/src/page/settings/view.js @@ -105,52 +105,56 @@ class SettingsPage extends React.PureComponent { - - {__('Notifications')} - - {__('Choose the notifications you would like to receive.')} - - - - {__('Subscriptions')} - - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_SUBSCRIPTION_NOTIFICATIONS, value); - }} - /> - - + {false && ( + + + {__('Notifications')} + + {__('Choose the notifications you would like to receive.')} + + + + {__('Subscriptions')} + + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_SUBSCRIPTION_NOTIFICATIONS, value); + }} + /> + + - - - {__('Rewards')} - - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_REWARD_NOTIFICATIONS, value); - }} - /> - - + + + {__('Rewards')} + + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_REWARD_NOTIFICATIONS, value); + }} + /> + + - - - {__('Tags you follow')} + + + {__('Tags you follow')} + + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_INTERESTS_NOTIFICATIONS, value); + }} + /> + + - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_INTERESTS_NOTIFICATIONS, value); - }} - /> - - + )} {false && ( From 51e3dfcf6a240fc2575edbf5f4860c42729c10d4 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 1 Nov 2019 06:52:39 +0100 Subject: [PATCH 6/8] show notification settings. handle blackListedOutpoints being null. --- src/component/fileItem/view.js | 4 +- src/component/fileListItem/view.js | 4 +- src/page/settings/view.js | 94 ++++++++++++++---------------- src/page/splash/view.js | 5 +- 4 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/component/fileItem/view.js b/src/component/fileItem/view.js index cf2db92..6e5235d 100644 --- a/src/component/fileItem/view.js +++ b/src/component/fileItem/view.js @@ -66,7 +66,9 @@ class FileItem extends React.PureComponent { let shouldHide = false; if (blackListedOutpoints || filteredOutpoints) { - const outpointsToHide = blackListedOutpoints.concat(filteredOutpoints); + const outpointsToHide = !blackListedOutpoints + ? filteredOutpoints + : blackListedOutpoints.concat(filteredOutpoints); shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout); } if (shouldHide) { diff --git a/src/component/fileListItem/view.js b/src/component/fileListItem/view.js index c2faa83..48f2c4d 100644 --- a/src/component/fileListItem/view.js +++ b/src/component/fileListItem/view.js @@ -120,7 +120,9 @@ class FileListItem extends React.PureComponent { shortChannelUri = signingChannel ? signingChannel.short_url : null; if (blackListedOutpoints || filteredOutpoints) { - const outpointsToHide = blackListedOutpoints.concat(filteredOutpoints); + const outpointsToHide = !blackListedOutpoints + ? filteredOutpoints + : blackListedOutpoints.concat(filteredOutpoints); shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout); } diff --git a/src/page/settings/view.js b/src/page/settings/view.js index 2b17b86..7272461 100644 --- a/src/page/settings/view.js +++ b/src/page/settings/view.js @@ -105,56 +105,52 @@ class SettingsPage extends React.PureComponent { - {false && ( - - - {__('Notifications')} - - {__('Choose the notifications you would like to receive.')} - - - - {__('Subscriptions')} - - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_SUBSCRIPTION_NOTIFICATIONS, value); - }} - /> - - - - - - {__('Rewards')} - - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_REWARD_NOTIFICATIONS, value); - }} - /> - - - - - - {__('Tags you follow')} - - - { - this.setNativeBooleanSetting(SETTINGS.RECEIVE_INTERESTS_NOTIFICATIONS, value); - }} - /> - - + + {__('Notifications')} + + {__('Choose the notifications you would like to receive.')} + + + + {__('Subscriptions')} - )} + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_SUBSCRIPTION_NOTIFICATIONS, value); + }} + /> + + + + + + {__('Rewards')} + + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_REWARD_NOTIFICATIONS, value); + }} + /> + + + + + + {__('Content Interests')} + + + { + this.setNativeBooleanSetting(SETTINGS.RECEIVE_INTERESTS_NOTIFICATIONS, value); + }} + /> + + {false && ( diff --git a/src/page/splash/view.js b/src/page/splash/view.js index 4aa5615..e288417 100644 --- a/src/page/splash/view.js +++ b/src/page/splash/view.js @@ -158,7 +158,10 @@ class SplashScreen extends React.PureComponent { NativeModules.VersionInfo.getAppVersion().then(appVersion => { this.setState({ shouldAuthenticate: true }); NativeModules.Firebase.getMessagingToken() - .then(firebaseToken => authenticate(appVersion, Platform.OS, firebaseToken)) + .then(firebaseToken => { + console.log(firebaseToken); + authenticate(appVersion, Platform.OS, firebaseToken); + }) .catch(() => authenticate(appVersion, Platform.OS)); }); } From 61189b817a47f75fb8d030a942766a5946200c19 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 6 Nov 2019 13:26:39 +0100 Subject: [PATCH 7/8] display unsupported content view --- src/page/file/view.js | 25 ++++++++++++++++++++++++- src/styles/filePage.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/page/file/view.js b/src/page/file/view.js index 0318d8e..dcf4d5e 100644 --- a/src/page/file/view.js +++ b/src/page/file/view.js @@ -6,6 +6,7 @@ import { Alert, DeviceEventEmitter, Dimensions, + Image, Linking, NativeModules, ScrollView, @@ -739,6 +740,7 @@ class FilePage extends React.PureComponent { const isWebViewable = mediaType === 'text'; const canOpen = isViewable && completed; const localFileUri = this.localUriForFileInfo(fileInfo); + const unsupported = !isPlayable && !canOpen; const openFile = () => { if (mediaType === 'image') { @@ -809,9 +811,30 @@ class FilePage extends React.PureComponent { thumbnail={thumbnail} /> )} - {(!this.state.downloadButtonShown || this.state.downloadPressed) && !this.state.mediaLoaded && ( + {!unsupported && + (!this.state.downloadButtonShown || this.state.downloadPressed) && + !this.state.mediaLoaded && ( )} + + {unsupported && fileInfo && completed && ( + + + + Unsupported Content + + Sorry, we are unable to display this content in the app. You can find the file named{' '} + {fileInfo.file_name} in your + downloads folder. + + + + )} + {((isPlayable && !completed && !canLoadMedia) || canOpen || (!completed && !this.state.streamingMode)) && diff --git a/src/styles/filePage.js b/src/styles/filePage.js index 6f15861..58d71eb 100644 --- a/src/styles/filePage.js +++ b/src/styles/filePage.js @@ -402,6 +402,39 @@ const filePageStyle = StyleSheet.create({ marginTop: 12, marginBottom: 12, }, + unsupportedContent: { + position: 'absolute', + left: 0, + right: 0, + top: 0, + bottom: 16, + padding: 24, + flexDirection: 'row', + alignItems: 'center', + backgroundColor: Colors.White, + }, + unspportedContentTextContainer: { + flex: 1, + }, + unsupportedContentFilename: { + color: Colors.LbryGreen, + fontFamily: 'Inter-UI-SemiBold', + fontSize: 16, + }, + unsupportedContentImage: { + width: 64, + height: 80, + marginRight: 24, + }, + unsupportedContentTitle: { + fontFamily: 'Inter-UI-Regular', + fontSize: 20, + }, + unsupportedContentText: { + fontFamily: 'Inter-UI-Regular', + fontSize: 16, + marginTop: 4, + }, }); export default filePageStyle; From 232cdb3d296dbb6703a491f513708620030da1fd Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 6 Nov 2019 13:41:05 +0100 Subject: [PATCH 8/8] disable send button if the recipient address is not valid --- src/component/walletSend/view.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/component/walletSend/view.js b/src/component/walletSend/view.js index f1d33ae..e06e25b 100644 --- a/src/component/walletSend/view.js +++ b/src/component/walletSend/view.js @@ -82,7 +82,8 @@ class WalletSend extends React.PureComponent { render() { const { balance } = this.props; - const canSend = this.state.address && this.state.amount > 0 && this.state.address.trim().length > 0; + const canSend = + this.state.address && this.state.amount > 0 && this.state.address.trim().length > 0 && this.state.addressValid; return ( @@ -94,7 +95,7 @@ class WalletSend extends React.PureComponent { this.setState({ address: value, addressChanged: true, - addressValid: value.trim().length == 0 || regexAddress.test(value), + addressValid: value.trim().length === 0 || regexAddress.test(value), }) } onBlur={this.handleAddressInputBlur}