From 8f609fa900c4a9cd5c78e9be84104d09c55df7e7 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 22 Feb 2019 04:28:11 +0100 Subject: [PATCH] 0.5.0 rc (#436) * fixes for release * fix subscriptions view. change Latest First to Latest Only. * fix channel subscription uri * fix subscription notifications * some iconography and label changes * change sdk log level for release builds * sort all subscriptions by newest first * fix crash with Picasso thumbnail fetch operation * add check for null / undefined filenames after stopping download * update sdk to 0.32.3. fix download notification. --- app/package-lock.json | 4 +-- app/package.json | 2 +- app/src/component/AppNavigator.js | 6 ++-- app/src/component/subscribeButton/view.js | 4 +-- app/src/page/discover/view.js | 29 ++++++++++--------- app/src/page/subscriptions/view.js | 5 ++-- app/src/redux/actions/file.js | 20 ++++++++++--- buildozer.spec.sample | 2 +- buildozer.spec.travis | 2 +- buildozer.spec.vagrant | 2 +- .../reactmodules/DownloadManagerModule.java | 25 ++++++++++++++++ .../browser/reactmodules/UtilityModule.java | 2 +- src/main/python/lbrynetservice.py | 27 ++++++++--------- 13 files changed, 84 insertions(+), 46 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 9588c367..2a53839e 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -4060,8 +4060,8 @@ } }, "lbry-redux": { - "version": "github:lbryio/lbry-redux#42c185e922a7c6091b0e1580bacbfd8e02f45a91", - "from": "github:lbryio/lbry-redux#031sdk-resolve", + "version": "github:lbryio/lbry-redux#3ab065b11a52d3e2e6a50a25459f9ff0aac03b13", + "from": "github:lbryio/lbry-redux", "requires": { "proxy-polyfill": "0.1.6", "reselect": "^3.0.0", diff --git a/app/package.json b/app/package.json index eaa02be9..49b2d78b 100644 --- a/app/package.json +++ b/app/package.json @@ -8,7 +8,7 @@ "dependencies": { "base-64": "^0.1.0", "@expo/vector-icons": "^8.1.0", - "lbry-redux": "lbryio/lbry-redux", + "lbry-redux": "lbryio/lbry-redux#old-search", "lbryinc": "lbryio/lbryinc", "moment": "^2.22.1", "react": "16.2.0", diff --git a/app/src/component/AppNavigator.js b/app/src/component/AppNavigator.js index 54eb6d15..4d51565f 100644 --- a/app/src/component/AppNavigator.js +++ b/app/src/component/AppNavigator.js @@ -126,7 +126,7 @@ const mySubscriptionsStack = createStackNavigator({ Subscriptions: { screen: SubscriptionsPage, navigationOptions: ({ navigation }) => ({ - title: 'My Subscriptions', + title: 'Subscriptions', headerLeft: menuNavigationButton(navigation), headerTitleStyle: discoverStyle.titleText }) @@ -173,13 +173,13 @@ const drawer = createDrawerNavigator({ title: 'Trending', drawerIcon: ({ tintColor }) => }}, MySubscriptionsStack: { screen: mySubscriptionsStack, navigationOptions: { - title: 'My Subscriptions', drawerIcon: ({ tintColor }) => + title: 'Subscriptions', drawerIcon: ({ tintColor }) => }}, WalletStack: { screen: walletStack, navigationOptions: { title: 'Wallet', drawerIcon: ({ tintColor }) => }}, Rewards: { screen: rewardsStack, navigationOptions: { - drawerIcon: ({ tintColor }) => + drawerIcon: ({ tintColor }) => }}, MyLBRYStack: { screen: myLbryStack, navigationOptions: { title: 'Downloads', drawerIcon: ({ tintColor }) => diff --git a/app/src/component/subscribeButton/view.js b/app/src/component/subscribeButton/view.js index 92013331..7225708b 100644 --- a/app/src/component/subscribeButton/view.js +++ b/app/src/component/subscribeButton/view.js @@ -1,5 +1,5 @@ import React from 'react'; -import { parseURI } from 'lbry-redux'; +import { normalizeURI, parseURI } from 'lbry-redux'; import { NativeModules, Text, View, TouchableOpacity } from 'react-native'; import Button from '../button'; import Colors from '../../styles/colors'; @@ -39,7 +39,7 @@ class SubscribeButton extends React.PureComponent { onPress={() => { subscriptionHandler({ channelName: claimName, - uri, + uri: normalizeURI(uri), }); }} /> ); diff --git a/app/src/page/discover/view.js b/app/src/page/discover/view.js index fc59e43c..9dfcef2a 100644 --- a/app/src/page/discover/view.js +++ b/app/src/page/discover/view.js @@ -10,7 +10,7 @@ import { Text, View } from 'react-native'; -import { normalizeURI, parseURI } from 'lbry-redux'; +import { Lbry, normalizeURI, parseURI } from 'lbry-redux'; import moment from 'moment'; import Constants from 'constants'; import Colors from 'styles/colors'; @@ -64,6 +64,7 @@ class DiscoverPage extends React.PureComponent { if (allSubscriptions) { for (let i = 0; i < allSubscriptions.length; i++) { const sub = allSubscriptions[i]; + if (sub.claim_id === claimId && sub.name === claimName && sub.channel_name === channelName) { return sub; } @@ -74,7 +75,7 @@ class DiscoverPage extends React.PureComponent { } componentDidUpdate(prevProps, prevState) { - const { allSubscriptions, unreadSubscriptions, enabledChannelNotifications } = this.props; + const { unreadSubscriptions, enabledChannelNotifications } = this.props; const utility = NativeModules.UtilityModule; if (utility) { @@ -89,18 +90,20 @@ class DiscoverPage extends React.PureComponent { // check if notifications are enabled for the channel if (enabledChannelNotifications.indexOf(channelName) > -1) { uris.forEach(uri => { - const sub = this.subscriptionForUri(uri, channelName); - if (sub && sub.value && sub.value.stream) { - let isPlayable = false; - const source = sub.value.stream.source; - const metadata = sub.value.stream.metadata; - if (source) { - isPlayable = source.contentType && ['audio', 'video'].indexOf(source.contentType.substring(0, 5)) > -1; + Lbry.resolve({ urls: uri }).then(result => { + const sub = result[uri].claim; + if (sub && sub.value && sub.value.stream) { + let isPlayable = false; + const source = sub.value.stream.source; + const metadata = sub.value.stream.metadata; + if (source) { + isPlayable = source.contentType && ['audio', 'video'].indexOf(source.contentType.substring(0, 5)) > -1; + } + if (metadata) { + utility.showNotificationForContent(uri, metadata.title, channelName, metadata.thumbnail, isPlayable); + } } - if (metadata) { - utility.showNotificationForContent(uri, metadata.title, channelName, metadata.thumbnail, isPlayable); - } - } + }); }); } }); diff --git a/app/src/page/subscriptions/view.js b/app/src/page/subscriptions/view.js index 875e0d11..14ada1db 100644 --- a/app/src/page/subscriptions/view.js +++ b/app/src/page/subscriptions/view.js @@ -6,10 +6,11 @@ import { FlatList, NativeModules, SectionList, + ScrollView, Text, View } from 'react-native'; -import { buildURI } from 'lbry-redux'; +import { buildURI, parseURI } from 'lbry-redux'; import { uriFromFileInfo } from 'utils/helper'; import moment from 'moment'; import Colors from 'styles/colors'; @@ -76,7 +77,7 @@ class SubscriptionsPage extends React.PureComponent { onPress={() => this.changeViewMode(Constants.SUBSCRIPTIONS_VIEW_ALL)} /> this.changeViewMode(Constants.SUBSCRIPTIONS_VIEW_LATEST_FIRST)} diff --git a/app/src/redux/actions/file.js b/app/src/redux/actions/file.js index 661a490a..be7e09b6 100644 --- a/app/src/redux/actions/file.js +++ b/app/src/redux/actions/file.js @@ -54,7 +54,13 @@ export function doUpdateLoadStatus(uri, outpoint) { }); if (NativeModules.LbryDownloadManager) { - NativeModules.LbryDownloadManager.updateDownload(uri, fileInfo.file_name, 100, writtenBytes, totalBytes); + NativeModules.LbryDownloadManager.updateDownload( + uri, + fileInfo.file_name ? fileInfo.file_name : '', + 100, + writtenBytes ? writtenBytes : 0, + totalBytes ? totalBytes : 0 + ); } // Once a download has been completed, delete the individual blob files to save space @@ -84,7 +90,13 @@ export function doUpdateLoadStatus(uri, outpoint) { }); if (NativeModules.LbryDownloadManager) { - NativeModules.LbryDownloadManager.updateDownload(uri, fileInfo.file_name, progress, writtenBytes, totalBytes); + NativeModules.LbryDownloadManager.updateDownload( + uri, + fileInfo.file_name ? fileInfo.file_name : '', + progress ? progress : 0, + writtenBytes ? writtenBytes : 0, + totalBytes ? totalBytes: 0 + ); } setTimeout(() => { @@ -118,7 +130,7 @@ export function doStartDownload(uri, outpoint) { }); if (NativeModules.LbryDownloadManager) { - NativeModules.LbryDownloadManager.startDownload(uri, fileInfo.file_name); + NativeModules.LbryDownloadManager.startDownload(uri, fileInfo.file_name ? fileInfo.file_name : ''); } dispatch(doUpdateLoadStatus(uri, outpoint)); @@ -146,7 +158,7 @@ export function doStopDownloadingFile(uri, fileInfo) { dispatch(doDeleteFile(fileInfo.outpoint, uri)); if (NativeModules.LbryDownloadManager) { - NativeModules.LbryDownloadManager.stopDownload(uri, fileInfo.file_name); + NativeModules.LbryDownloadManager.stopDownload(uri, fileInfo.file_name ? fileInfo.file_name : ''); } }); }; diff --git a/buildozer.spec.sample b/buildozer.spec.sample index 293d2adb..716cd2f1 100644 --- a/buildozer.spec.sample +++ b/buildozer.spec.sample @@ -36,7 +36,7 @@ version.filename = %(source.dir)s/main.py # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy -requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.0#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve +requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.3#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/buildozer.spec.travis b/buildozer.spec.travis index 293d2adb..716cd2f1 100644 --- a/buildozer.spec.travis +++ b/buildozer.spec.travis @@ -36,7 +36,7 @@ version.filename = %(source.dir)s/main.py # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy -requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.0#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve +requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.3#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/buildozer.spec.vagrant b/buildozer.spec.vagrant index 293d2adb..716cd2f1 100644 --- a/buildozer.spec.vagrant +++ b/buildozer.spec.vagrant @@ -36,7 +36,7 @@ version.filename = %(source.dir)s/main.py # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy -requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.0#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve +requirements = python3crystax, openssl, sqlite3, hostpython3crystax, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, miniupnpc==1.9, gmpy, appdirs==1.4.3, argparse==1.2.1, docopt, base58==1.0.0, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2, pyyaml, qrcode==5.2.2, requests, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, txJSON-RPC, zope.interface==4.3.3, protobuf==3.6.1, keyring==10.4.0, txupnp, git+https://github.com/lbryio/lbryschema.git#egg=lbryschema, git+https://github.com/lbryio/lbry.git@v0.32.3#egg=lbrynet, git+https://github.com/lbryio/aioupnp.git#egg=aioupnp, asn1crypto, treq==17.8.0, funcsigs, mock, pbr, pyopenssl, twisted, idna, Automat, hyperlink, PyHamcrest, netifaces, cryptography, aiohttp==3.4.4, multidict==4.5.2, idna_ssl==1.1.0, typing_extensions==3.6.5, yarl, chardet==3.0.4, async_timeout==3.0.1, aiorpcX==0.9.0, git+https://github.com/lbryio/torba#egg=torba, coincurve # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/src/main/java/io/lbry/browser/reactmodules/DownloadManagerModule.java b/src/main/java/io/lbry/browser/reactmodules/DownloadManagerModule.java index 6d6bae9d..97624e37 100644 --- a/src/main/java/io/lbry/browser/reactmodules/DownloadManagerModule.java +++ b/src/main/java/io/lbry/browser/reactmodules/DownloadManagerModule.java @@ -32,6 +32,8 @@ public class DownloadManagerModule extends ReactContextBaseJavaModule { private HashMap downloadIdNotificationIdMap = new HashMap(); + private HashMap stoppedDownloadsMap = new HashMap(); + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#"); private static final int MAX_FILENAME_LENGTH = 20; @@ -115,6 +117,10 @@ public class DownloadManagerModule extends ReactContextBaseJavaModule { @ReactMethod public void startDownload(String id, String filename) { + if (filename == null || filename.trim().length() == 0) { + return; + } + createNotificationChannel(); createNotificationGroup(); @@ -129,6 +135,7 @@ public class DownloadManagerModule extends ReactContextBaseJavaModule { .setSmallIcon(android.R.drawable.stat_sys_download); int notificationId = getNotificationId(id); + downloadIdNotificationIdMap.put(id, notificationId); builders.put(notificationId, builder); notificationManager.notify(notificationId, builder.build()); @@ -140,11 +147,23 @@ public class DownloadManagerModule extends ReactContextBaseJavaModule { @ReactMethod public void updateDownload(String id, String filename, double progress, double writtenBytes, double totalBytes) { + if (filename == null || filename.trim().length() == 0) { + return; + } + int notificationId = getNotificationId(id); if (notificationId == -1) { return; } + if (stoppedDownloadsMap.containsKey(id) && stoppedDownloadsMap.get(id)) { + // if this happens, the download was canceled, so remove the notification + // TODO: Figure out why updateDownload is called in the React Native code after stopDownload + removeDownloadNotification(id); + stoppedDownloadsMap.remove(id); + return; + } + createNotificationChannel(); createNotificationGroup(); @@ -198,6 +217,12 @@ public class DownloadManagerModule extends ReactContextBaseJavaModule { @ReactMethod public void stopDownload(String id, String filename) { + android.util.Log.d("ReactNativeJS", "Stop download for id=" + id + "; filename=" + filename); + stoppedDownloadsMap.put(id, true); + removeDownloadNotification(id); + } + + private void removeDownloadNotification(String id) { if (!downloadIdNotificationIdMap.containsKey(id)) { return; } diff --git a/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java b/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java index 36db16eb..5e470653 100644 --- a/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java +++ b/src/main/java/io/lbry/browser/reactmodules/UtilityModule.java @@ -244,7 +244,7 @@ public class UtilityModule extends ReactContextBaseJavaModule { protected Bitmap doInBackground(Void... params) { try { return Picasso.get().load(thumbnailUri).get(); - } catch (IOException e) { + } catch (Exception e) { return null; } } diff --git a/src/main/python/lbrynetservice.py b/src/main/python/lbrynetservice.py index d321033a..95fc25df 100644 --- a/src/main/python/lbrynetservice.py +++ b/src/main/python/lbrynetservice.py @@ -64,7 +64,7 @@ def configure_logging(conf): logging.getLogger('aioupnp').setLevel(logging.WARNING) logging.getLogger('aiohttp').setLevel(logging.CRITICAL) - logging.getLogger('lbrynet').setLevel(logging.DEBUG) + logging.getLogger('lbrynet').setLevel(logging.DEBUG if lbrynet_android_utils.isDebug() else logging.INFO) logging.getLogger('torba').setLevel(logging.INFO) loggly_handler = get_loggly_handler() @@ -90,21 +90,18 @@ def start(): log.info('Starting lbry sdk {}'.format(lbrynet_version)); loop = asyncio.get_event_loop() - loop.set_debug(True) + loop.set_debug(lbrynet_android_utils.isDebug()) - if check_connection(): - daemon = Daemon(conf) - try: - loop.run_until_complete(daemon.start()) - loop.run_until_complete(daemon.stop_event.wait()) - except (GracefulExit): - pass - finally: - loop.run_until_complete(daemon.stop()) - if hasattr(loop, 'shutdown_asyncgens'): - loop.run_until_complete(loop.shutdown_asyncgens()) - else: - print("Not connected to internet, unable to start") + daemon = Daemon(conf) + try: + loop.run_until_complete(daemon.start()) + loop.run_until_complete(daemon.stop_event.wait()) + except (GracefulExit): + pass + finally: + loop.run_until_complete(daemon.stop()) + if hasattr(loop, 'shutdown_asyncgens'): + loop.run_until_complete(loop.shutdown_asyncgens()) if __name__ == '__main__': start()