[RN] Replace cached image implementation
Use react-native-fastimage, which uses 2 full-native image impleentations using well known and mature (native) libraries. This gets us rid of 2 libraries which were observerd as a source of bugs and created trouble with dependencies: react-native-fetch-blob and react-native-img-cache. They are also no longer well maintained.
This commit is contained in:
parent
f5a667ad9e
commit
27021ea271
|
@ -68,3 +68,9 @@
|
|||
-dontwarn java.nio.file.*
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
-dontwarn okio.**
|
||||
|
||||
# FastImage
|
||||
|
||||
-keep public class com.dylanvann.fastimage.* {*;}
|
||||
-keep public class com.dylanvann.fastimage.** {*;}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ dependencies {
|
|||
compile 'com.facebook.react:react-native:+'
|
||||
|
||||
compile project(':react-native-background-timer')
|
||||
compile project(':react-native-fetch-blob')
|
||||
compile project(':react-native-fast-image')
|
||||
compile project(':react-native-immersive')
|
||||
compile project(':react-native-keep-awake')
|
||||
compile project(':react-native-linear-gradient')
|
||||
|
|
|
@ -122,12 +122,12 @@ class ReactInstanceManagerHolder {
|
|||
.addPackage(new com.BV.LinearGradient.LinearGradientPackage())
|
||||
.addPackage(new com.calendarevents.CalendarEventsPackage())
|
||||
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
|
||||
.addPackage(new com.dylanvann.fastimage.FastImageViewPackage())
|
||||
.addPackage(new com.facebook.react.shell.MainReactPackage())
|
||||
.addPackage(new com.i18n.reactnativei18n.ReactNativeI18n())
|
||||
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
|
||||
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
|
||||
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
|
||||
.addPackage(new com.RNFetchBlob.RNFetchBlobPackage())
|
||||
.addPackage(new com.rnimmersive.RNImmersivePackage())
|
||||
.addPackage(new com.zmxv.RNSound.RNSoundPackage())
|
||||
.addPackage(new ReactPackageAdapter() {
|
||||
|
|
|
@ -3,8 +3,8 @@ rootProject.name = 'jitsi-meet'
|
|||
include ':app', ':sdk'
|
||||
include ':react-native-background-timer'
|
||||
project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android')
|
||||
include ':react-native-fetch-blob'
|
||||
project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android')
|
||||
include ':react-native-fast-image'
|
||||
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
|
||||
include ':react-native-immersive'
|
||||
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
|
||||
include ':react-native-keep-awake'
|
||||
|
|
|
@ -28,8 +28,8 @@ target 'JitsiMeet' do
|
|||
|
||||
pod 'react-native-background-timer',
|
||||
:path => '../node_modules/react-native-background-timer'
|
||||
pod 'react-native-fetch-blob',
|
||||
:path => '../node_modules/react-native-fetch-blob'
|
||||
pod 'react-native-fast-image',
|
||||
:path => '../node_modules/react-native-fast-image'
|
||||
pod 'react-native-keep-awake',
|
||||
:path => '../node_modules/react-native-keep-awake'
|
||||
pod 'react-native-locale-detector',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
PODS:
|
||||
- boost-for-react-native (1.63.0)
|
||||
- DoubleConversion (1.1.5)
|
||||
- FLAnimatedImage (1.0.12)
|
||||
- Folly (2016.09.26.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
|
@ -12,8 +13,11 @@ PODS:
|
|||
- React
|
||||
- react-native-calendar-events (1.6.0):
|
||||
- React
|
||||
- react-native-fetch-blob (0.10.6):
|
||||
- React/Core
|
||||
- react-native-fast-image (4.0.14):
|
||||
- FLAnimatedImage
|
||||
- React
|
||||
- SDWebImage/Core
|
||||
- SDWebImage/GIF
|
||||
- react-native-keep-awake (2.0.6):
|
||||
- React
|
||||
- react-native-locale-detector (1.0.0):
|
||||
|
@ -68,6 +72,10 @@ PODS:
|
|||
- React/Core
|
||||
- RNVectorIcons (4.4.2):
|
||||
- React
|
||||
- SDWebImage/Core (4.4.1)
|
||||
- SDWebImage/GIF (4.4.1):
|
||||
- FLAnimatedImage (~> 1.0)
|
||||
- SDWebImage/Core
|
||||
- yoga (0.55.4.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
|
@ -76,7 +84,7 @@ DEPENDENCIES:
|
|||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
|
||||
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
|
||||
- react-native-fetch-blob (from `../node_modules/react-native-fetch-blob`)
|
||||
- react-native-fast-image (from `../node_modules/react-native-fast-image`)
|
||||
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
|
||||
- react-native-locale-detector (from `../node_modules/react-native-locale-detector`)
|
||||
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
|
||||
|
@ -98,6 +106,8 @@ DEPENDENCIES:
|
|||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- boost-for-react-native
|
||||
- FLAnimatedImage
|
||||
- SDWebImage
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
DoubleConversion:
|
||||
|
@ -112,8 +122,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-background-timer"
|
||||
react-native-calendar-events:
|
||||
:path: "../node_modules/react-native-calendar-events"
|
||||
react-native-fetch-blob:
|
||||
:path: "../node_modules/react-native-fetch-blob"
|
||||
react-native-fast-image:
|
||||
:path: "../node_modules/react-native-fast-image"
|
||||
react-native-keep-awake:
|
||||
:path: "../node_modules/react-native-keep-awake"
|
||||
react-native-locale-detector:
|
||||
|
@ -132,20 +142,22 @@ EXTERNAL SOURCES:
|
|||
SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
DoubleConversion: e22e0762848812a87afd67ffda3998d9ef29170c
|
||||
FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31
|
||||
Folly: 211775e49d8da0ca658aebc8eab89d642935755c
|
||||
glog: 1de0bb937dccdc981596d3b5825ebfb765017ded
|
||||
React: aa2040dbb6f317b95314968021bd2888816e03d5
|
||||
react-native-background-timer: 63dcbf37dbcf294b5c6c071afcdc661fa06a7594
|
||||
react-native-calendar-events: fe6fbc8ed337a7423c98f2c9012b25f20444de09
|
||||
react-native-fetch-blob: 63394b1d7b0781547b3e4463b3195790177b1222
|
||||
react-native-fast-image: cba3d9bf9c2cf8ddb643d887a686c53a5dd90a2c
|
||||
react-native-keep-awake: 0de4bd66de0c23178107dce0c2fcc3354b2a8e94
|
||||
react-native-locale-detector: d1b2c6fe5abb56e3a1efb6c2d6f308c05c4251f1
|
||||
react-native-webrtc: 31b6d3f1e3e2ce373aa43fd682b04367250f807d
|
||||
ReactNativePermissions: 9f2d9c45c98800795e6c2ed330e25d11a66a8169
|
||||
RNSound: b360b3862d3118ed1c74bb9825696b5957686ac4
|
||||
RNVectorIcons: c0dbfbf6068fefa240c37b0f71bd03b45dddac44
|
||||
SDWebImage: 47e9b5b925cbce75946c23f0c42dd19464189af4
|
||||
yoga: a23273df0088bf7f2bb7e5d7b00044ea57a2a54a
|
||||
|
||||
PODFILE CHECKSUM: e24d0131e937934fbe4d1f0b7ad5947ee0192f58
|
||||
PODFILE CHECKSUM: 1d5c8382f73d9540fac68d93b32e1d3b58d069ee
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
|
|
@ -5573,11 +5573,6 @@
|
|||
"randomfill": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"crypto-js": {
|
||||
"version": "3.1.9-1",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
|
||||
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
|
||||
},
|
||||
"css-color-list": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/css-color-list/-/css-color-list-0.0.1.tgz",
|
||||
|
@ -12715,35 +12710,12 @@
|
|||
"jssha": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"react-native-fetch-blob": {
|
||||
"version": "github:joltup/react-native-fetch-blob#1f9a1761aea4e37bd672bd0d233f3adf0e113a11",
|
||||
"from": "github:joltup/react-native-fetch-blob#1f9a1761aea4e37bd672bd0d233f3adf0e113a11",
|
||||
"react-native-fast-image": {
|
||||
"version": "4.0.14",
|
||||
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-4.0.14.tgz",
|
||||
"integrity": "sha512-MeRgL70JxoY/hn8ZRGBsDED9SGvTEeznneL//fWZyLaG0CM+w2CH4QXAMvADnIvu2RFd8WQWNii6c6VOpVe4Tg==",
|
||||
"requires": {
|
||||
"base-64": "0.1.0",
|
||||
"glob": "7.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
|
||||
"integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.2",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-img-cache": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-img-cache/-/react-native-img-cache-1.5.2.tgz",
|
||||
"integrity": "sha1-6HG4MJk3t/mSbgmwFuTk5nWKOfo=",
|
||||
"requires": {
|
||||
"crypto-js": "^3.1.9-1"
|
||||
"prop-types": "^15.5.10"
|
||||
}
|
||||
},
|
||||
"react-native-immersive": {
|
||||
|
|
|
@ -60,8 +60,7 @@
|
|||
"react-native-background-timer": "2.0.0",
|
||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#cad37355f36d17587d84af72b0095e8cc5fd3df9",
|
||||
"react-native-callstats": "3.52.0",
|
||||
"react-native-fetch-blob": "github:joltup/react-native-fetch-blob#1f9a1761aea4e37bd672bd0d233f3adf0e113a11",
|
||||
"react-native-img-cache": "1.5.2",
|
||||
"react-native-fast-image": "4.0.14",
|
||||
"react-native-immersive": "1.1.0",
|
||||
"react-native-keep-awake": "2.0.6",
|
||||
"react-native-linear-gradient": "2.4.0",
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Image, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import { CachedImage, ImageCache } from '../../../mobile/image-cache';
|
||||
import { Platform } from '../../react';
|
||||
import { ColorPalette } from '../../styles';
|
||||
|
||||
import styles from './styles';
|
||||
|
@ -46,7 +45,8 @@ type Props = {
|
|||
*/
|
||||
type State = {
|
||||
backgroundColor: string,
|
||||
source: number | { uri: string }
|
||||
source: ?{ uri: string },
|
||||
useDefaultAvatar: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -68,6 +68,9 @@ export default class Avatar extends Component<Props, State> {
|
|||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onAvatarLoaded = this._onAvatarLoaded.bind(this);
|
||||
|
||||
// Fork (in Facebook/React speak) the prop uri because Image will
|
||||
// receive it through a source object. Additionally, other props may be
|
||||
// forked as well.
|
||||
|
@ -94,18 +97,8 @@ export default class Avatar extends Component<Props, State> {
|
|||
if (prevURI !== nextURI || assignState) {
|
||||
const nextState = {
|
||||
backgroundColor: this._getBackgroundColor(nextProps),
|
||||
|
||||
/**
|
||||
* The source of the {@link Image} which is the actual
|
||||
* representation of this {@link Avatar}. The state
|
||||
* {@code source} was explicitly introduced in order to reduce
|
||||
* unnecessary renders.
|
||||
*
|
||||
* @type {{
|
||||
* uri: string
|
||||
* }}
|
||||
*/
|
||||
source: _DEFAULT_SOURCE
|
||||
source: undefined,
|
||||
useDefaultAvatar: true
|
||||
};
|
||||
|
||||
if (assignState) {
|
||||
|
@ -130,7 +123,14 @@ export default class Avatar extends Component<Props, State> {
|
|||
// an image retrieval action.
|
||||
if (nextURI && !nextURI.startsWith('#')) {
|
||||
const nextSource = { uri: nextURI };
|
||||
const observer = () => {
|
||||
|
||||
if (assignState) {
|
||||
// eslint-disable-next-line react/no-direct-mutation-state
|
||||
this.state = {
|
||||
...this.state,
|
||||
source: nextSource
|
||||
};
|
||||
} else {
|
||||
this._unmounted || this.setState((prevState, props) => {
|
||||
if (props.uri === nextURI
|
||||
&& (!prevState.source
|
||||
|
@ -140,22 +140,6 @@ export default class Avatar extends Component<Props, State> {
|
|||
|
||||
return {};
|
||||
});
|
||||
};
|
||||
|
||||
// Wait for the source/URI to load.
|
||||
if (ImageCache) {
|
||||
ImageCache.get().on(
|
||||
nextSource,
|
||||
observer,
|
||||
/* immutable */ true);
|
||||
} else if (assignState) {
|
||||
// eslint-disable-next-line react/no-direct-mutation-state
|
||||
this.state = {
|
||||
...this.state,
|
||||
source: nextSource
|
||||
};
|
||||
} else {
|
||||
observer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,107 +187,115 @@ export default class Avatar extends Component<Props, State> {
|
|||
return `hsl(${hash % 360}, 100%, 75%)`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper which computes the style for the {@code Image} / {@code FastImage}
|
||||
* component.
|
||||
*
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getImageStyle() {
|
||||
const { size } = this.props;
|
||||
|
||||
return {
|
||||
...styles.avatar,
|
||||
borderRadius: size / 2,
|
||||
height: size,
|
||||
width: size
|
||||
};
|
||||
}
|
||||
|
||||
_onAvatarLoaded: () => void;
|
||||
|
||||
/**
|
||||
* Handler called when the remote image was loaded. When this happens we
|
||||
* show that instead of the default locally generated one.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onAvatarLoaded() {
|
||||
this._unmounted || this.setState({ useDefaultAvatar: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a default, locally generated avatar image.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderDefaultAvatar() {
|
||||
// When using a local image, react-native-fastimage falls back to a
|
||||
// regular Image, so we need to wrap it in a view to make it round.
|
||||
// https://github.com/facebook/react-native/issues/3198
|
||||
|
||||
const { backgroundColor, useDefaultAvatar } = this.state;
|
||||
const imageStyle = this._getImageStyle();
|
||||
const viewStyle = {
|
||||
...imageStyle,
|
||||
|
||||
backgroundColor,
|
||||
display: useDefaultAvatar ? 'flex' : 'none',
|
||||
|
||||
// FIXME @lyubomir: Without the opacity bellow I feel like the
|
||||
// avatar colors are too strong. Besides, we use opacity for the
|
||||
// ToolbarButtons. That's where I copied the value from and we
|
||||
// may want to think about "standardizing" the opacity in the
|
||||
// app in a way similar to ColorPalette.
|
||||
opacity: 0.1,
|
||||
overflow: 'hidden'
|
||||
};
|
||||
|
||||
return (
|
||||
<View style = { viewStyle }>
|
||||
<Image
|
||||
|
||||
// The Image adds a fade effect without asking, so lets
|
||||
// explicitly disable it. More info here:
|
||||
// https://github.com/facebook/react-native/issues/10194
|
||||
fadeDuration = { 0 }
|
||||
resizeMode = 'contain'
|
||||
source = { _DEFAULT_SOURCE }
|
||||
style = { imageStyle } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an avatar using a remote image.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderAvatar() {
|
||||
const { source, useDefaultAvatar } = this.state;
|
||||
const style = {
|
||||
...this._getImageStyle(),
|
||||
display: useDefaultAvatar ? 'none' : 'flex'
|
||||
};
|
||||
|
||||
return (
|
||||
<FastImage
|
||||
onLoad = { this._onAvatarLoaded }
|
||||
resizeMode = 'contain'
|
||||
source = { source }
|
||||
style = { style } />
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
// Propagate all props of this Avatar but the ones consumed by this
|
||||
// Avatar to the Image it renders.
|
||||
const {
|
||||
/* eslint-disable no-unused-vars */
|
||||
const { source, useDefaultAvatar } = this.state;
|
||||
|
||||
// The following are forked in state:
|
||||
uri: forked0,
|
||||
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
size,
|
||||
...props
|
||||
} = this.props;
|
||||
const {
|
||||
backgroundColor,
|
||||
source
|
||||
} = this.state;
|
||||
|
||||
// Compute the base style
|
||||
const borderRadius = size / 2;
|
||||
const style = {
|
||||
...styles.avatar,
|
||||
|
||||
// XXX Workaround for Android: for radii < 80 the border radius
|
||||
// doesn't work properly, but applying a radius twice as big seems
|
||||
// to do the trick.
|
||||
borderRadius:
|
||||
Platform.OS === 'android' && borderRadius < 80
|
||||
? size * 2
|
||||
: borderRadius,
|
||||
height: size,
|
||||
width: size
|
||||
};
|
||||
|
||||
// If we're rendering the _DEFAULT_SOURCE, then we want to do some
|
||||
// additional fu like having automagical colors generated per
|
||||
// participant, transparency to make the intermediate state while
|
||||
// downloading the remote image a little less "in your face", etc.
|
||||
let styleWithBackgroundColor;
|
||||
|
||||
if (source === _DEFAULT_SOURCE && backgroundColor) {
|
||||
styleWithBackgroundColor = {
|
||||
...style,
|
||||
|
||||
backgroundColor,
|
||||
|
||||
// FIXME @lyubomir: Without the opacity bellow I feel like the
|
||||
// avatar colors are too strong. Besides, we use opacity for the
|
||||
// ToolbarButtons. That's where I copied the value from and we
|
||||
// may want to think about "standardizing" the opacity in the
|
||||
// app in a way similar to ColorPalette.
|
||||
opacity: 0.1,
|
||||
overflow: 'hidden'
|
||||
};
|
||||
}
|
||||
|
||||
// If we're styling with backgroundColor, we need to wrap the Image in a
|
||||
// View because of a bug in React Native for Android:
|
||||
// https://github.com/facebook/react-native/issues/3198
|
||||
let imageStyle;
|
||||
let viewStyle;
|
||||
|
||||
if (styleWithBackgroundColor) {
|
||||
if (Platform.OS === 'android') {
|
||||
imageStyle = style;
|
||||
viewStyle = styleWithBackgroundColor;
|
||||
} else {
|
||||
imageStyle = styleWithBackgroundColor;
|
||||
}
|
||||
} else {
|
||||
imageStyle = style;
|
||||
}
|
||||
|
||||
let element
|
||||
= React.createElement(
|
||||
|
||||
// XXX CachedImage removed support for images which clearly do
|
||||
// not need caching.
|
||||
typeof source === 'number' ? Image : CachedImage,
|
||||
{
|
||||
...props,
|
||||
|
||||
// The Image adds a fade effect without asking, so lets
|
||||
// explicitly disable it. More info here:
|
||||
// https://github.com/facebook/react-native/issues/10194
|
||||
fadeDuration: 0,
|
||||
resizeMode: 'contain',
|
||||
source,
|
||||
style: imageStyle
|
||||
});
|
||||
|
||||
if (viewStyle) {
|
||||
element = React.createElement(View, { style: viewStyle }, element);
|
||||
}
|
||||
|
||||
return element;
|
||||
return (
|
||||
<Fragment>
|
||||
{ source && this._renderAvatar() }
|
||||
{ useDefaultAvatar && this._renderDefaultAvatar() }
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../i18n';
|
||||
|
@ -11,7 +12,6 @@ import {
|
|||
shouldRenderVideoTrack,
|
||||
VideoTrack
|
||||
} from '../../media';
|
||||
import { prefetch } from '../../../mobile/image-cache';
|
||||
import { Container, TintedView } from '../../react';
|
||||
import { TestHint } from '../../testing/components';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../../tracks';
|
||||
|
@ -303,7 +303,8 @@ function _mapStateToProps(state, ownProps) {
|
|||
|
||||
// ParticipantView knows before Avatar that an avatar URL will be used
|
||||
// so it's advisable to prefetch here.
|
||||
avatar && prefetch({ uri: avatar });
|
||||
avatar && !avatar.startsWith('#')
|
||||
&& FastImage.preload([ { uri: avatar } ]);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { ImageCache } from './';
|
||||
|
||||
/**
|
||||
* Notifies about the successful download of an {@code Image} source. The name
|
||||
* is inspired by {@code Image}. The downloaded {@code Image} source is not
|
||||
* available because (1) I do not know how to get it from {@link ImageCache} and
|
||||
* (2) we do not need it bellow. The function was explicitly introduced to cut
|
||||
* down on unnecessary {@code ImageCache} {@code observer} instances.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _onLoad() {
|
||||
// ImageCache requires an observer; otherwise, we do not need it because we
|
||||
// merely want to initiate the download and do not care what happens with it
|
||||
// afterwards.
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the retrieval of a specific {@code Image} source (if it has not
|
||||
* been initiated already). Due to limitations of {@link ImageCache}, the source
|
||||
* may have at most one {@code uri}. The name is inspired by {@code Image}.
|
||||
*
|
||||
* @param {Object} source - The {@code Image} source with preferably exactly
|
||||
* one {@code uri}.
|
||||
* @public
|
||||
* @returns {void}
|
||||
*/
|
||||
export function prefetch(source) {
|
||||
ImageCache && ImageCache.get().on(source, _onLoad, /* immutable */ true);
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
export * from './functions';
|
||||
export * from './react-native-img-cache';
|
||||
|
||||
import './middleware';
|
|
@ -1,91 +0,0 @@
|
|||
/* @flow */
|
||||
|
||||
import { APP_WILL_MOUNT } from '../../base/app';
|
||||
import {
|
||||
getAvatarURL,
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
PARTICIPANT_ID_CHANGED,
|
||||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_UPDATED
|
||||
} from '../../base/participants';
|
||||
import { MiddlewareRegistry } from '../../base/redux';
|
||||
|
||||
import { ImageCache, prefetch } from './';
|
||||
|
||||
/**
|
||||
* The indicator which determines whether avatar URLs are to be prefetched in
|
||||
* the middleware here. Unless/until the implementation starts observing the
|
||||
* redux store instead of the respective redux actions, the value should very
|
||||
* likely be {@code false} because the middleware here is pretty much the last
|
||||
* to get a chance to figure out that an avatar URL may be used. Besides, it is
|
||||
* somewhat uninformed to download just about anything that may eventually be
|
||||
* used or not.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
const _PREFETCH_AVATAR_URLS = false;
|
||||
|
||||
/**
|
||||
* Middleware which captures app startup and conference actions in order to
|
||||
* clear the image cache.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(({ getState }) => next => action => {
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
// XXX CONFERENCE_FAILED/LEFT are no longer used here because they
|
||||
// are tricky to get right as detectors of the moments in time at which
|
||||
// CachedImage is not used. Anyway, if ImageCache is to be cleared from
|
||||
// time to time, SET_LOCATION_URL is a much easier detector of such
|
||||
// opportune times. Fixes at least one 100%-reproducible case of
|
||||
// "TypeError: Cannot read property handlers of undefined." Anyway, in
|
||||
// order to reduce the re-downloading of the same avatars, eventually we
|
||||
// decided to not clear during the runtime of the app (other that at the
|
||||
// beginning that is).
|
||||
ImageCache && ImageCache.get().clear();
|
||||
break;
|
||||
|
||||
case PARTICIPANT_ID_CHANGED:
|
||||
case PARTICIPANT_JOINED:
|
||||
case PARTICIPANT_UPDATED: {
|
||||
if (!_PREFETCH_AVATAR_URLS) {
|
||||
break;
|
||||
}
|
||||
|
||||
const result = next(action);
|
||||
|
||||
// Initiate the downloads of participants' avatars as soon as possible.
|
||||
|
||||
// 1. Figure out the participant (instance).
|
||||
let { participant } = action;
|
||||
|
||||
if (participant) {
|
||||
if (participant.id) {
|
||||
participant = getParticipantById(getState, participant.id);
|
||||
} else if (participant.local) {
|
||||
participant = getLocalParticipant(getState);
|
||||
} else {
|
||||
participant = undefined;
|
||||
}
|
||||
} else if (action.oldValue && action.newValue) {
|
||||
participant = getParticipantById(getState, action.newValue);
|
||||
}
|
||||
if (participant) {
|
||||
// 2. Get the participant's avatar URL.
|
||||
const uri = getAvatarURL(participant);
|
||||
|
||||
if (uri) {
|
||||
// 3. Initiate the download of the participant's avatar.
|
||||
prefetch({ uri });
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
export * from './react-native-img-cache.yes';
|
|
@ -1 +0,0 @@
|
|||
export * from './react-native-img-cache.yes';
|
|
@ -1,16 +0,0 @@
|
|||
// XXX The third-party react-native modules react-native-fetch-blob utilizes the
|
||||
// same HTTP library as react-native i.e. okhttp. Unfortunately, that means that
|
||||
// the versions of okhttp on which react-native and react-native-fetch-blob
|
||||
// depend may have incompatible APIs. Such an incompatibility will be made
|
||||
// apparent at compile time and the developer doing the compilation may choose
|
||||
// to not compile react-native-fetch-blob's source code.
|
||||
|
||||
// XXX The choice between the use of react-native-img-cache could've been done
|
||||
// at runtime based on whether NativeModules.RNFetchBlob is defined if only
|
||||
// react-native-fetch-blob would've completely protected itself. At the time of
|
||||
// this writing its source code appears to be attempting to protect itself from
|
||||
// missing native binaries but that protection is incomplete and there's a
|
||||
// TypeError.
|
||||
|
||||
import { Image } from 'react-native';
|
||||
export { Image as CachedImage, undefined as ImageCache };
|
|
@ -1 +0,0 @@
|
|||
export { CachedImage, ImageCache } from 'react-native-img-cache';
|
Loading…
Reference in New Issue