better performance on lower end devices with react-native-fast-image (#275)

* thumbnail aspect ratio sizing tweaks
* show approximate values for formatted bytes
* truncate titles over 80 characters in the file item list component
This commit is contained in:
Akinwale Ariwodola 2018-09-01 22:04:50 +01:00 committed by GitHub
parent e9abbf256e
commit 4b7be60c27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 31 deletions

16
app/package-lock.json generated
View file

@ -3969,8 +3969,17 @@
"version": "github:lbryio/lbryinc#678c5098e2099dd1560b2fefa2795f38ca3ce07b", "version": "github:lbryio/lbryinc#678c5098e2099dd1560b2fefa2795f38ca3ce07b",
"from": "github:lbryio/lbryinc", "from": "github:lbryio/lbryinc",
"requires": { "requires": {
"lbry-redux": "github:lbryio/lbry-redux#31f7afa8a37f5741dac01fc1ecdf153f3bed95dc",
"reselect": "^3.0.0" "reselect": "^3.0.0"
},
"dependencies": {
"lbry-redux": {
"version": "github:lbryio/lbry-redux#31f7afa8a37f5741dac01fc1ecdf153f3bed95dc",
"from": "github:lbryio/lbry-redux#31f7afa8a37f5741dac01fc1ecdf153f3bed95dc",
"requires": {
"proxy-polyfill": "0.1.6",
"reselect": "^3.0.0"
}
}
} }
}, },
"lcid": { "lcid": {
@ -5188,6 +5197,11 @@
"react-native-drawer-layout": "1.3.2" "react-native-drawer-layout": "1.3.2"
} }
}, },
"react-native-fast-image": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.0.3.tgz",
"integrity": "sha512-70XlQPt8b7yQSMwUEEIN5jTx7KOx1EBD2XhIRIEHChfNv5Gwn8dh28RSo/Dq9qezf4CWJXO3CAb4lq+Hu9d0vw=="
},
"react-native-fetch-blob": { "react-native-fetch-blob": {
"version": "0.10.8", "version": "0.10.8",
"resolved": "https://registry.npmjs.org/react-native-fetch-blob/-/react-native-fetch-blob-0.10.8.tgz", "resolved": "https://registry.npmjs.org/react-native-fetch-blob/-/react-native-fetch-blob-0.10.8.tgz",

View file

@ -12,6 +12,7 @@
"moment": "^2.22.1", "moment": "^2.22.1",
"react": "16.2.0", "react": "16.2.0",
"react-native": "0.55.3", "react-native": "0.55.3",
"react-native-fast-image": "^5.0.3",
"react-native-fetch-blob": "^0.10.8", "react-native-fetch-blob": "^0.10.8",
"react-native-image-zoom-viewer": "^2.2.5", "react-native-image-zoom-viewer": "^2.2.5",
"react-native-vector-icons": "^5.0.0", "react-native-vector-icons": "^5.0.0",

View file

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { ActivityIndicator, Image, Text, View } from 'react-native'; import { ActivityIndicator, Image, Text, View } from 'react-native';
import Colors from '../../styles/colors'; import Colors from '../../styles/colors';
import FastImage from 'react-native-fast-image'
import fileItemMediaStyle from '../../styles/fileItemMedia'; import fileItemMediaStyle from '../../styles/fileItemMedia';
class FileItemMedia extends React.PureComponent { class FileItemMedia extends React.PureComponent {
@ -18,6 +19,10 @@ class FileItemMedia extends React.PureComponent {
fileItemMediaStyle.autothumbOrange, fileItemMediaStyle.autothumbOrange,
]; ];
state: {
imageLoadFailed: false
};
componentWillMount() { componentWillMount() {
this.setState({ this.setState({
autoThumbStyle: autoThumbStyle:
@ -27,21 +32,47 @@ class FileItemMedia extends React.PureComponent {
}); });
} }
getFastImageResizeMode(resizeMode) {
switch (resizeMode) {
case "contain":
return FastImage.resizeMode.contain;
case "stretch":
console.log('using stretch resize mode...');
return FastImage.resizeMode.stretch;
case "center":
return FastImage.resizeMode.center;
default:
return FastImage.resizeMode.cover;
}
}
render() { render() {
let style = this.props.style; let style = this.props.style;
const { blurRadius, isResolvingUri, thumbnail, title, resizeMode } = this.props; const { blurRadius, isResolvingUri, thumbnail, title, resizeMode } = this.props;
const atStyle = this.state.autoThumbStyle; const atStyle = this.state.autoThumbStyle;
if (thumbnail && ((typeof thumbnail) === 'string') && !this.state.imageLoadFailed) {
if (thumbnail && ((typeof thumbnail) === 'string')) {
if (style == null) { if (style == null) {
style = fileItemMediaStyle.thumbnail; style = fileItemMediaStyle.thumbnail;
} }
if (blurRadius > 0) {
// No blur radius support in FastImage yet
return ( return (
<Image source={{uri: thumbnail}} <Image
source={{uri: thumbnail}}
blurRadius={blurRadius} blurRadius={blurRadius}
resizeMode={resizeMode ? resizeMode : "cover"} resizeMode={resizeMode ? resizeMode : "cover"}
style={style} /> style={style}
/>);
}
return (
<FastImage
source={{uri: thumbnail}}
onError={() => this.setState({ imageLoadFailed: true })}
resizeMode={this.getFastImageResizeMode(resizeMode)}
style={style}
/>
); );
} }

View file

@ -27,19 +27,27 @@ class FileListItem extends React.PureComponent {
formatBytes = (bytes) => { formatBytes = (bytes) => {
if (bytes < 1048576) { // < 1MB if (bytes < 1048576) { // < 1MB
const value = (bytes / 1024.0).toFixed(2); const value = (bytes / 1024.0).toFixed(0);
return `${value} KB`; return `${value} KB`;
} }
if (bytes < 1073741824) { // < 1GB if (bytes < 1073741824) { // < 1GB
const value = (bytes / (1024.0 * 1024.0)).toFixed(2); const value = (bytes / (1024.0 * 1024.0)).toFixed(0);
return `${value} MB`; return `${value} MB`;
} }
const value = (bytes / (1024.0 * 1024.0 * 1024.0)).toFixed(2); const value = (bytes / (1024.0 * 1024.0 * 1024.0)).toFixed(0);
return `${value} GB`; return `${value} GB`;
} }
formatTitle = (title) => {
if (!title) {
return title;
}
return (title.length > 80) ? title.substring(0, 77).trim() + '...' : title;
}
getDownloadProgress = (fileInfo) => { getDownloadProgress = (fileInfo) => {
return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100); return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
} }
@ -85,7 +93,7 @@ class FileListItem extends React.PureComponent {
</View> </View>
</View>)} </View>)}
{!isResolving && <Text style={fileListStyle.title}>{title || name}</Text>} {!isResolving && <Text style={fileListStyle.title}>{this.formatTitle(title) || this.formatTitle(name)}</Text>}
{!isResolving && channel && {!isResolving && channel &&
<Link style={fileListStyle.publisher} text={channel} onPress={() => { <Link style={fileListStyle.publisher} text={channel} onPress={() => {
const channelUri = normalizeURI(channel); const channelUri = normalizeURI(channel);

View file

@ -1,14 +1,17 @@
import { Dimensions, StyleSheet } from 'react-native'; import { Dimensions, PixelRatio, StyleSheet } from 'react-native';
import Colors from './colors'; import Colors from './colors';
const screenDimension = Dimensions.get('window'); const screenDimension = Dimensions.get('window');
const screenWidth = screenDimension.width; const screenWidth = screenDimension.width;
const screenHeight = screenDimension.height; const screenHeight = screenDimension.height;
const screenWidthPixels = PixelRatio.getPixelSizeForLayoutSize(screenWidth);
const screenHeightPixels = PixelRatio.getPixelSizeForLayoutSize(screenHeight);
console.log('screenHeightPixels=' + screenHeightPixels);
// calculate thumbnail width and height based on device's aspect ratio // calculate thumbnail width and height based on device's aspect ratio
const horizontalMargin = 48; // left and right margins (24 + 24) const horizontalMargin = 48; // left and right margins (24 + 24)
const verticalMargin = (screenWidth / screenHeight) * horizontalMargin; const verticalMargin = (screenWidthPixels > 720 && screenHeightPixels > 1920) ? 0 : ((screenWidthPixels <= 720) ? 20 : 16);
const mediaWidth = screenWidth - horizontalMargin; const mediaWidth = screenWidth - horizontalMargin;
const mediaHeight = (screenWidth / (screenHeight - verticalMargin)) * mediaWidth; const mediaHeight = ((screenWidth / screenHeight) * ((screenWidthPixels <= 720) ? screenWidth : mediaWidth)) - verticalMargin;
const discoverStyle = StyleSheet.create({ const discoverStyle = StyleSheet.create({
container: { container: {

View file

@ -1,18 +1,21 @@
import { Dimensions, StyleSheet } from 'react-native'; import { Dimensions, PixelRatio, StyleSheet } from 'react-native';
import Colors from './colors'; import Colors from './colors';
const screenDimension = Dimensions.get('window'); const screenDimension = Dimensions.get('window');
const screenWidth = screenDimension.width; const screenWidth = screenDimension.width;
const screenHeight = screenDimension.height; const screenHeight = screenDimension.height;
const thumbnailHeight = 100; const screenWidthPixels = PixelRatio.getPixelSizeForLayoutSize(screenWidth);
const thumbnailWidth = (screenHeight / screenWidth) * thumbnailHeight; const screenHeightPixels = PixelRatio.getPixelSizeForLayoutSize(screenHeight);
const verticalAdjust = (screenHeightPixels > 1280 && screenHeightPixels <= 1920) ? 6 : 0;
const thumbnailWidth = (screenWidthPixels <= 720) ? 144 : 156;
const thumbnailHeight = ((screenWidth / screenHeight) * thumbnailWidth) - verticalAdjust;
const fileListStyle = StyleSheet.create({ const fileListStyle = StyleSheet.create({
item: { item: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
marginTop: 16 marginTop: 8
}, },
detailsContainer: { detailsContainer: {
flex: 1 flex: 1
@ -20,37 +23,37 @@ const fileListStyle = StyleSheet.create({
thumbnail: { thumbnail: {
width: thumbnailWidth, width: thumbnailWidth,
height: thumbnailHeight, height: thumbnailHeight,
marginRight: 16, marginRight: (screenWidthPixels <= 720) ? 10 : 12,
justifyContent: 'center' justifyContent: 'center'
}, },
title: { title: {
fontFamily: 'Metropolis-SemiBold', fontFamily: 'Metropolis-SemiBold',
fontSize: 16 fontSize: (screenWidthPixels <= 720) ? 12 : 16
}, },
uri: { uri: {
fontFamily: 'Metropolis-SemiBold', fontFamily: 'Metropolis-SemiBold',
fontSize: 14, fontSize: (screenWidthPixels <= 720) ? 12 : 14,
marginBottom: 8 marginBottom: 8
}, },
publisher: { publisher: {
fontFamily: 'Metropolis-SemiBold', fontFamily: 'Metropolis-SemiBold',
fontSize: 14, fontSize: (screenWidthPixels <= 720) ? 12 : 14,
marginTop: 3, marginTop: (screenWidthPixels <= 720) ? 1 : 3,
color: Colors.LbryGreen color: Colors.LbryGreen
}, },
loading: { loading: {
position: 'absolute' position: 'absolute'
}, },
downloadInfo: { downloadInfo: {
marginTop: 8 marginTop: (screenWidthPixels <= 720) ? 4 : 8
}, },
downloadStorage: { downloadStorage: {
fontFamily: 'Metropolis-Regular', fontFamily: 'Metropolis-Regular',
fontSize: 14, fontSize: (screenWidthPixels <= 720) ? 12 : 14,
color: Colors.ChannelGrey color: Colors.ChannelGrey
}, },
progress: { progress: {
marginTop: 4, marginTop: (screenWidthPixels <= 720) ? 2 : 4,
height: 3, height: 3,
flex: 1, flex: 1,
flexDirection: 'row' flexDirection: 'row'

View file

@ -21,7 +21,7 @@ const searchStyle = StyleSheet.create({
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
marginTop: 16 marginTop: 8
}, },
searchInput: { searchInput: {
width: '100%', width: '100%',

View file

@ -40,6 +40,10 @@ android {
} }
} }
dexOptions {
jumboMode true
}
{% if args.sign -%} {% if args.sign -%}
signingConfigs { signingConfigs {
release { release {
@ -80,8 +84,9 @@ subprojects {
} }
dependencies { dependencies {
compile project(':react-native-video') compile project(':react-native-fast-image')
compile project(':react-native-fetch-blob') compile project(':react-native-fetch-blob')
compile project(':react-native-video')
{%- for aar in aars %} {%- for aar in aars %}
compile(name: '{{ aar }}', ext: 'aar') compile(name: '{{ aar }}', ext: 'aar')
{%- endfor -%} {%- endfor -%}

View file

@ -1,5 +1,7 @@
rootProject.name = 'browser' rootProject.name = 'browser'
include ':react-native-video' include ':react-native-fast-image'
project(':react-native-video').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-video/android-exoplayer') project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-fast-image/android')
include ':react-native-fetch-blob' include ':react-native-fetch-blob'
project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-fetch-blob/android') project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-fetch-blob/android')
include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-video/android-exoplayer')

View file

@ -20,6 +20,7 @@ import android.telephony.TelephonyManager;
import android.widget.Toast; import android.widget.Toast;
import com.brentvatne.react.ReactVideoPackage; import com.brentvatne.react.ReactVideoPackage;
import com.dylanvann.fastimage.FastImageViewPackage;
import com.facebook.react.common.LifecycleState; import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.ReactRootView; import com.facebook.react.ReactRootView;
@ -103,6 +104,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
.setBundleAssetName("index.android.bundle") .setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index") .setJSMainModulePath("index")
.addPackage(new MainReactPackage()) .addPackage(new MainReactPackage())
.addPackage(new FastImageViewPackage())
.addPackage(new ReactVideoPackage()) .addPackage(new ReactVideoPackage())
.addPackage(new RNFetchBlobPackage()) .addPackage(new RNFetchBlobPackage())
.addPackage(new LbryReactPackage()) .addPackage(new LbryReactPackage())