From e7ade2d1af1c29f416c5898bdb201325992d67b8 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 13 Sep 2016 11:36:49 +0800 Subject: [PATCH 01/35] add onTopRight to TopBar for customing right button on TopBar --- .DS_Store | Bin 0 -> 6148 bytes lib/bar/TopBar.js | 10 ++++++++++ lib/index.js | 6 ++++++ 3 files changed, 16 insertions(+) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..eebe0e172333ccb66e4b87edcacd69c74df15855 GIT binary patch literal 6148 zcmeHKISv9b4733uBpOP}e1RVX1TWwN6d)P|5?8$y@8W5Uj|LVxXwZ1&OyYR5+9~3- zi0JIHo`{S@WB@mmn+Tk#S#nVM=AV(@d1)de?#&Tr!e*yo{ z|38zsq5@RluN2VUd^w-tld`t9KF(@wfv@0}bBCK@?i37Oj)7i|v9NMH_N2%wHphNV VYyzE*xYL3B88BUFRN&VNJOI!L6`=qC literal 0 HcmV?d00001 diff --git a/lib/bar/TopBar.js b/lib/bar/TopBar.js index b5e1169..18ad094 100644 --- a/lib/bar/TopBar.js +++ b/lib/bar/TopBar.js @@ -33,6 +33,9 @@ export default class TopBar extends React.Component { title, height, onBack, + onTopRight, + topRightView, + topRightStyle, } = this.props; return ( @@ -49,6 +52,9 @@ export default class TopBar extends React.Component { } {title} + + {topRightView} + ); } @@ -75,4 +81,8 @@ const styles = StyleSheet.create({ paddingTop: 14, marginLeft: -10, }, + topRightContainer: { + position: 'relative', + flexDirection: 'row', + }, }); diff --git a/lib/index.js b/lib/index.js index ef1c5f6..8cb9bef 100644 --- a/lib/index.js +++ b/lib/index.js @@ -196,6 +196,9 @@ export default class PhotoBrowser extends React.Component { onActionButton, onBack, itemPerRow, + onTopRight, + topRightView, + topRightStyle, } = this.props; const { dataSource, @@ -266,6 +269,9 @@ export default class PhotoBrowser extends React.Component { displayed={displayTopBar} title={isFullScreen ? title : `${mediaList.length} photos`} onBack={onBack} + onTopRight={onTopRight} + topRightView={topRightView} + topRightStyle={topRightStyle} /> ); From 75f264468f6d65e8427e5d81af627c35f44b09b9 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 13 Sep 2016 13:35:17 +0800 Subject: [PATCH 02/35] try to fix the top right layout --- lib/.DS_Store | Bin 0 -> 6148 bytes lib/bar/TopBar.js | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 lib/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..75b7babc42848b55d71c69407b6120182203d769 GIT binary patch literal 6148 zcmeH~J!%6%427R!7lt%jx}3%b$PET#pTHN0L%@x3z>w5)^gR7ES*H$5cmnB-G%I%Z zD|S`@Z2$TG0!#olbXV*=%*>dt@P;$)U#I)+`f0pQvfVyTmjO&;ssLc!1UOG})p;=82 zR;?Ceh}WZ?+UmMqI#RP8R>OzYoz15hnq@nzF`-!xQ4j$Um=RcIKKc27r2jVm&svm< zfC&6E0=7P!4tu^-ovjbA=k?dB`g+i*aXG_}p8zI)6mRKa+;6_1_R^8c3Qa!(fk8n8 H{*=Hsf+`Vy literal 0 HcmV?d00001 diff --git a/lib/bar/TopBar.js b/lib/bar/TopBar.js index 18ad094..67b4a71 100644 --- a/lib/bar/TopBar.js +++ b/lib/bar/TopBar.js @@ -82,7 +82,9 @@ const styles = StyleSheet.create({ marginLeft: -10, }, topRightContainer: { - position: 'relative', + position: 'absolute', flexDirection: 'row', + right: 0, + top: 16, }, }); From 3805642936b62c8ad1ea345ad1c1e24ebea82d21 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 13 Sep 2016 15:18:32 +0800 Subject: [PATCH 03/35] try to silence the PropTypes warning --- lib/FullScreenContainer.js | 28 ++++++++++++++-------------- lib/GridContainer.js | 8 ++++---- lib/bar/BarContainer.js | 8 ++++---- lib/bar/BottomBar.js | 22 +++++++++++----------- lib/bar/TopBar.js | 10 +++++----- lib/index.js | 26 +++++++++++++------------- lib/media/Photo.js | 26 +++++++++++++------------- 7 files changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index f9a5c45..ac5e5b4 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -19,40 +19,40 @@ export default class FullScreenContainer extends React.Component { static propTypes = { style: View.propTypes.style, - dataSource: PropTypes.instanceOf(ListView.DataSource).isRequired, - mediaList: PropTypes.array.isRequired, + dataSource: React.PropTypes.instanceOf(ListView.DataSource).isRequired, + mediaList: React.PropTypes.array.isRequired, /* * opens grid view */ - onGridButtonTap: PropTypes.func, + onGridButtonTap: React.PropTypes.func, /* * updates top bar title */ - updateTitle: PropTypes.func, + updateTitle: React.PropTypes.func, /* * displays/hides top bar */ - toggleTopBar: PropTypes.func, + toggleTopBar: React.PropTypes.func, /* * refresh the list to apply selection change */ - onMediaSelection: PropTypes.func, + onMediaSelection: React.PropTypes.func, /* * those props are inherited from main PhotoBrowser component * i.e. index.js */ - initialIndex: PropTypes.number, - alwaysShowControls: PropTypes.bool, - displayActionButton: PropTypes.bool, - displayNavArrows: PropTypes.bool, - displaySelectionButtons: PropTypes.bool, - enableGrid: PropTypes.bool, - useCircleProgress: PropTypes.bool, - onActionButton: PropTypes.func, + initialIndex: React.PropTypes.number, + alwaysShowControls: React.PropTypes.bool, + displayActionButton: React.PropTypes.bool, + displayNavArrows: React.PropTypes.bool, + displaySelectionButtons: React.PropTypes.bool, + enableGrid: React.PropTypes.bool, + useCircleProgress: React.PropTypes.bool, + onActionButton: React.PropTypes.func, }; static defaultProps = { diff --git a/lib/GridContainer.js b/lib/GridContainer.js index f534079..aea7ee1 100644 --- a/lib/GridContainer.js +++ b/lib/GridContainer.js @@ -18,14 +18,14 @@ export default class GridContainer extends React.Component { static propTypes = { style: View.propTypes.style, dataSource: PropTypes.instanceOf(ListView.DataSource).isRequired, - displaySelectionButtons: PropTypes.bool, - onPhotoTap: PropTypes.func, - itemPerRow: PropTypes.number, + displaySelectionButtons: React.PropTypes.bool, + onPhotoTap: React.PropTypes.func, + itemPerRow: React.PropTypes.number, /* * refresh the list to apply selection change */ - onMediaSelection: PropTypes.func, + onMediaSelection: React.PropTypes.func, }; static defaultProps = { diff --git a/lib/bar/BarContainer.js b/lib/bar/BarContainer.js index d2c7418..d58f0d0 100644 --- a/lib/bar/BarContainer.js +++ b/lib/bar/BarContainer.js @@ -14,10 +14,10 @@ class BarContainer extends Component { static propTypes = { style: View.propTypes.style, - position: PropTypes.oneOf([BAR_POSITIONS.TOP, BAR_POSITIONS.BOTTOM]), - displayed: PropTypes.bool, - height: PropTypes.number, - children: PropTypes.node, + position: React.PropTypes.oneOf([BAR_POSITIONS.TOP, BAR_POSITIONS.BOTTOM]), + displayed: React.PropTypes.bool, + height: React.PropTypes.number, + children: React.PropTypes.node, }; static defaultProps = { diff --git a/lib/bar/BottomBar.js b/lib/bar/BottomBar.js index 9a2aea8..bbda5b1 100644 --- a/lib/bar/BottomBar.js +++ b/lib/bar/BottomBar.js @@ -13,17 +13,17 @@ const BUTTON_WIDTH = 40; export default class BottomBar extends React.Component { - static propTypes = { - displayed: PropTypes.bool, - height: PropTypes.number, - caption: PropTypes.string, - displayNavArrows: PropTypes.bool, - displayGridButton: PropTypes.bool, - displayActionButton: PropTypes.bool, - onPrev: PropTypes.func, - onNext: PropTypes.func, - onGrid: PropTypes.func, - onAction: PropTypes.func, + static PropTypes = { + displayed: React.PropTypes.bool, + height: React.PropTypes.number, + caption: React.PropTypes.string, + displayNavArrows: React.PropTypes.bool, + displayGridButton: React.PropTypes.bool, + displayActionButton: React.PropTypes.bool, + onPrev: React.PropTypes.func, + onNext: React.PropTypes.func, + onGrid: React.PropTypes.func, + onAction: React.PropTypes.func, }; static defaultProps = { diff --git a/lib/bar/TopBar.js b/lib/bar/TopBar.js index 67b4a71..b1e3293 100644 --- a/lib/bar/TopBar.js +++ b/lib/bar/TopBar.js @@ -11,11 +11,11 @@ import { BarContainer } from './BarContainer'; export default class TopBar extends React.Component { - static propTypes = { - displayed: PropTypes.bool, - title: PropTypes.string, - height: PropTypes.number, - onBack: PropTypes.func, + static PropTypes = { + displayed: React.PropTypes.bool, + title: React.PropTypes.string, + height: React.PropTypes.number, + onBack: React.PropTypes.func, }; static defaultProps = { diff --git a/lib/index.js b/lib/index.js index 8cb9bef..bd65396 100644 --- a/lib/index.js +++ b/lib/index.js @@ -18,70 +18,70 @@ const TOOLBAR_HEIGHT = Constants.TOOLBAR_HEIGHT; export default class PhotoBrowser extends React.Component { static propTypes = { - mediaList: PropTypes.array.isRequired, + mediaList: React.PropTypes.array.isRequired, /* * set the current visible photo before displaying */ - initialIndex: PropTypes.number, + initialIndex: React.PropTypes.number, /* * Allows to control whether the bars and controls are always visible * or whether they fade away to show the photo full */ - alwaysShowControls: PropTypes.bool, + alwaysShowControls: React.PropTypes.bool, /* * Show action button to allow sharing, copying, etc */ - displayActionButton: PropTypes.bool, + displayActionButton: React.PropTypes.bool, /* * Whether to display left and right nav arrows on bottom toolbar */ - displayNavArrows: PropTypes.bool, + displayNavArrows: React.PropTypes.bool, /* * Whether to allow the viewing of all the photo thumbnails on a grid */ - enableGrid: PropTypes.bool, + enableGrid: React.PropTypes.bool, /* * Whether to start on the grid of thumbnails instead of the first photo */ - startOnGrid: PropTypes.bool, + startOnGrid: React.PropTypes.bool, /* * Whether selection buttons are shown on each image */ - displaySelectionButtons: PropTypes.bool, + displaySelectionButtons: React.PropTypes.bool, /* * Called when a media item is selected or unselected */ - onSelectionChanged: PropTypes.func, + onSelectionChanged: React.PropTypes.func, /* * Called when action button is pressed for a media * If you don't provide this props, ActionSheetIOS will be opened as default */ - onActionButton: PropTypes.func, + onActionButton: React.PropTypes.func, /* * displays Progress.Circle instead of default Progress.Bar for full screen photos * iOS only */ - useCircleProgress: PropTypes.bool, + useCircleProgress: React.PropTypes.bool, /* * Called when done or back button is tapped */ - onBack: PropTypes.func, + onBack: React.PropTypes.func, /* * Sets images amount in grid row, default - 3 (defined in GridContainer) */ - itemPerRow: PropTypes.number, + itemPerRow: React.PropTypes.number, }; static defaultProps = { diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 5831e10..0f36a7a 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -17,63 +17,63 @@ export default class Photo extends Component { /* * image uri or opaque type that is passed as source object to image component */ - uri: PropTypes.oneOfType([ + uri: React.PropTypes.oneOfType([ // assets or http url - PropTypes.string, + React.PropTypes.string, // Opaque type returned by require('./image.jpg') - PropTypes.number, + React.PropTypes.number, ]).isRequired, /* * displays a check button above the image */ - displaySelectionButtons: PropTypes.bool, + displaySelectionButtons: React.PropTypes.bool, /* * image resizeMode */ - resizeMode: PropTypes.string, + resizeMode: React.PropTypes.string, /* * these values are set to image and it's container * screen width and height are used if those are not defined */ - width: PropTypes.number, - height: PropTypes.number, + width: React.PropTypes.number, + height: React.PropTypes.number, /* * when lazyLoad is true, * image is not loaded until 'load' method is manually executed */ - lazyLoad: PropTypes.bool, + lazyLoad: React.PropTypes.bool, /* * displays selected or unselected icon based on this prop */ - selected: PropTypes.bool, + selected: React.PropTypes.bool, /* * size of selection images are decided based on this */ - thumbnail: PropTypes.bool, + thumbnail: React.PropTypes.bool, /* * executed when user selects/unselects the photo */ - onSelection: PropTypes.func, + onSelection: React.PropTypes.func, /* * image tag generated using require(asset_path) */ - progressImage: PropTypes.number, + progressImage: React.PropTypes.number, /* * displays Progress.Circle instead of default Progress.Bar * it's ignored when progressImage is also passed. * iOS only */ - useCircleProgress: PropTypes.bool, + useCircleProgress: React.PropTypes.bool, }; static defaultProps = { From 558520f54e789a81999d63ced18ccb7ade695309 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 13 Sep 2016 16:21:48 +0800 Subject: [PATCH 04/35] update RN to 0.32.0, and the PropTypes warning cleared --- .DS_Store | Bin 6148 -> 6148 bytes lib/.DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 28 ++++++++++++++-------------- lib/GridContainer.js | 8 ++++---- lib/bar/BarContainer.js | 8 ++++---- lib/bar/BottomBar.js | 22 +++++++++++----------- lib/bar/TopBar.js | 10 +++++----- lib/index.js | 26 +++++++++++++------------- lib/media/Photo.js | 26 +++++++++++++------------- 9 files changed, 64 insertions(+), 64 deletions(-) diff --git a/.DS_Store b/.DS_Store index eebe0e172333ccb66e4b87edcacd69c74df15855..37e790363ec891b62bba449c4459449547555456 100644 GIT binary patch delta 393 zcmZoMXfc=|#>B)qu~2NHo+2aj!~pA!2O1cGj2`)VW`-PwOopVS^5TM|octsP21epxwCfJM(0I5nZryklqF$ R2GU?-Hiw98V4m2(0szh2amfGx delta 72 zcmZoMXfc=|#>CJzu~2NHo+2aT!~knX#>qTP@|#PTC$nsBU_QyTnVo~51E^$kA@g_U a$^0U^oQw<%3B)qu~3YagMop8V`8C*EEA9c0w9`^fkA+wxF9JfKMBZ@PAb?~xSX*b zB*V;*#E{5PlvIu^o0C~wVqkEKk%^gwm5rT)lZ%^&mz!6Bhntr-HaH`{Jh&vWq_o&6 zu_#_ZCO9)CH7T(uJTs*vBP2D?H7B(!HP64uC$S{8C>o?VBtJg~r~txFObW|PEsqxv zan8@HFG)H0ynfW*Aiu*~Ajq|BVm zl1i|tP=#Q2Kw?P-&^8W%shk{~@d6Un)rJO!Its?d2DLg0)#l~~ItnJnX0^2(oSY^c zvf5r@NtJDrS8qRjAhLxS02#${ivR!s delta 82 zcmZoMXfc=|#>AjHu~3+iak4G5v>+1$1TX?AAQoWQ?8&^3Wpe@ZN2bl}9Q+(W#hVkE azcWwf7g6K{DM|pTpKQXTyg5c>1v3C Date: Wed, 14 Sep 2016 13:03:49 +0800 Subject: [PATCH 05/35] try to add in zooming ability of photo --- lib/.DS_Store | Bin 6148 -> 6148 bytes lib/media/Photo.js | 4 +++- package.json | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/.DS_Store b/lib/.DS_Store index 72d389a1f348cb4950c2e77f369e3bb4a760fe7a..5c02d8fb95e40a014bb791b6944f98a8d40e01ca 100644 GIT binary patch delta 41 xcmZoMXfc@J&&a$nU^gQp^JX3 {error ? this._renderErrorIcon() : this._renderProgressIndicator()} - ", "homepage": "https://github.com/halilb/react-native-photo-browser#readme", "dependencies": { - "react-native-progress": "^3.0.0" + "react-native-progress": "^3.0.0", + "react-native-transformable-image": "0.0.18" } } From 8730d1138b8f56135e7f164f3ff4541a4232784c Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 14 Sep 2016 15:02:54 +0800 Subject: [PATCH 06/35] when start load photo update the transformable view state --- lib/.DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 1 + lib/media/Photo.js | 49 +++++++++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/.DS_Store b/lib/.DS_Store index 5c02d8fb95e40a014bb791b6944f98a8d40e01ca..29c73d491f803168f70ecc82b6ef368c7f1280ee 100644 GIT binary patch delta 218 zcmZoMXfc=|#>B!ku~2NHo+2a5#(>?7iyN4k7+E&+FoiOjCY2W#B<18MF)%RvOe)C9 zEG{uHxXH-G%)-jX&cVsW&CSilEg;Ah8=R3}9$b=GQd;bkSTy-8lf>j4ro?a#PEJk^ z&UgWd>S{w%V;u!!Q=?iPg=%wi104kuW3$>?fvFrE(we4@zL5pBU5gekS-Ncbio-{N ymH`1HBZOuUhSD(V*ydp7g^ZioIruq%F5g_p{GE9+zlb9TP(2e!&E^P^HOv5%Pcpjz delta 68 zcmZoMXfc=|#>B)qu~2NHo+2aj#(>?7jLe&PSV9>$m#|G{+}I$@yqTSYp9837vmnQJ W=E?jbjvNd?z{tSBvN=Lz4Kn~t91nN^ diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index f9a5c45..12624b5 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -216,6 +216,7 @@ export default class FullScreenContainer extends React.Component { lazyLoad useCircleProgress={useCircleProgress} uri={media.photo} + transformable={true} displaySelectionButtons={displaySelectionButtons} selected={media.selected} onSelection={(isSelected) => { diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 141cc14..9ecd16c 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -36,6 +36,11 @@ export default class Photo extends Component { */ resizeMode: PropTypes.string, + /* + * if transformable then photo can be zoomed + */ + transformable: PropTypes.bool, + /* * these values are set to image and it's container * screen width and height are used if those are not defined @@ -83,6 +88,7 @@ export default class Photo extends Component { thumbnail: false, lazyLoad: false, selected: false, + transformable: false, }; constructor(props) { @@ -103,6 +109,14 @@ export default class Photo extends Component { } load() { + if (this.transformableImage) { + const viewTransformer = this.transformableImage.getViewTransformerInstance(); + viewTransformer && viewTransformer.setState({ + scale: 1, + translateX: 0, + translateY: 0, + }); + }; if (!this.state.uri) { this.setState({ uri: this.props.uri, @@ -219,7 +233,7 @@ export default class Photo extends Component { } render() { - const { resizeMode, width, height } = this.props; + const { resizeMode, width, height, transformable } = this.props; const screen = Dimensions.get('window'); const { uri, error } = this.state; @@ -241,15 +255,30 @@ export default class Photo extends Component { return ( {error ? this._renderErrorIcon() : this._renderProgressIndicator()} - + { + transformable ? ( + this.transformableImage = ref} + style={[styles.image, sizeStyle]} + source={source} + onProgress={this._onProgress} + onError={this._onError} + onLoad={this._onLoad} + resizeMode={resizeMode} + /> + ) : ( + + ) + } {this._renderSelectionButton()} ); From ba1f0099de14506f8fc11c2fc24022137c5dcde4 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 14 Sep 2016 15:12:41 +0800 Subject: [PATCH 07/35] update the example --- .DS_Store | Bin 6148 -> 6148 bytes Example/PhotoBrowserExample.js | 17 +++++++++++++++++ Example/media/ic_delete.png | Bin 0 -> 2576 bytes Example/package.json | 4 ++-- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 Example/media/ic_delete.png diff --git a/.DS_Store b/.DS_Store index 37e790363ec891b62bba449c4459449547555456..cc7475e8c21667e3501f24600110552b616e964b 100644 GIT binary patch delta 44 zcmZoMXfc@J&&aYdU^gQp%VZuVd46^VSB46PM21|30)`xh)Xg$XXIVG1bNuB80QZv% AA^-pY delta 31 ncmZoMXfc@J&&a$nU^gQp^JE?-`OTh8`&cJ7$Zcll_{$Ffmi`Hg diff --git a/Example/PhotoBrowserExample.js b/Example/PhotoBrowserExample.js index 89a156e..85b09db 100644 --- a/Example/PhotoBrowserExample.js +++ b/Example/PhotoBrowserExample.js @@ -11,6 +11,7 @@ import { StyleSheet, Navigator, Text, + Image, TouchableOpacity, View, Platform, @@ -74,6 +75,7 @@ export default class PhotoBrowserExample extends Component { this._onActionButton = this._onActionButton.bind(this); this._renderRow = this._renderRow.bind(this); this._renderScene = this._renderScene.bind(this); + this._renderTopRightView = this._renderTopRightView.bind(this); const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2, @@ -105,6 +107,18 @@ export default class PhotoBrowserExample extends Component { this.refs.nav.push(example); } + _renderTopRightView() { + return ( + + + + + ); + } + _renderRow(rowData, sectionID, rowID) { const example = EXAMPLES[rowID]; @@ -154,6 +168,9 @@ export default class PhotoBrowserExample extends Component { useCircleProgress onSelectionChanged={this._onSelectionChanged} onActionButton={this._onActionButton} + onTopRight={() => console.log('on top right click')} + topRightView={this._renderTopRightView()} + topRightStyle={{overflow: 'hidden'}} /> ); } diff --git a/Example/media/ic_delete.png b/Example/media/ic_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..609c88fe1885cc5614558b376d961dc2258296af GIT binary patch literal 2576 zcmV+r3h(uaP)bza!KrZ6b=Bk7=fw)<^e1Px@G~CiD;-=t!|24&nO_GF95iUnV$_PtoIU;{{VPK zM1EMS)jk`${+S|4k~Ks$WM22o#a%`CDFC~YBv}(%mtZKD%WIkWpm~)$6=M#-jEFo1 zpe!Qy0=Si#_cHTk&?w#qf`+1$2_m|7%wXt>T8A+0?F(0%}D*i5jNoGDs zM4QvvCZf&e;ZB;eSF=CQ%=<&sJ6C9}uVv;ZS9yI;0Vrv$zZF7UABbo(fNujR8Jk{C z%&fK6S7*f~7;3fJdH_dPX+4RE494OpB7*>uRT{w&B3c)VV_S&G9stj`slYgZ8%m|p zxv{yHN~LoF++aBQ_&x(*S8T4!7#kbAkeTlU@P>!*(*X93jEr0mo2!kHk&z1k>@ysF zALZe(v9SxI5+$N_X6EMnq7%_jKMbK7Lr(y&d%6;i)|CL*2H}Pc_}H;y@6VM`KoHRfMC7Lc-gbRwn0ZHDL^i`cHeMv6 zJ-Lv`0p?@5=&0vuBHEa#aS{2n=fja`t*^?|cm#;ZZV`FGQQzNctv{ZL(ORwcQ4t}B z(c?sPc_u~+0OJ6IquwJ#ba8Nl0BR0nll?HNNDCrb2jCS){f`DUBqDb^j64TmTTnv< z1~cyvkv}?yezylP0N@({{%#F*{wgA04Pu~=Kty{0oUz0{1K?|^3I?#v;XnQtfbRt2 z-gf}-eE{!R4exhE^s$}`biaOiTRr^1Nndi%)%C>7SLl_QAgLn87U zOPjaQtrN;P?N3_;o%+AXXJK5zvzA8FT@_-Y6ZR;hI4;9LNE^a3jwstF(pjX&JgEh% zfSELeiU=aQ0>C^GUD0b9=FPV~e)AnYz${y{h}?q$c=e3P4L`bg~z%jLCb zbr>bRl4ypAJk)sNF~zn-?yePjfO_*jbCL)N(Myp2V~+wlqb&*>CD;X5Jgp4iTLP%flxkcdWQ+Vq)Ta0Jeks z;gCccaEZ;#FJ&QiULrTyd)TVi(<^RpbsI#qGYc|G<QJxzFK#q=>x zVhyAbyC@YVMSKT>7SleHgT=>*4RXCv=O^- zA}i(e9kmLL0>t!ev=KULSj-31_qVqQJ=gqWNN0ZtbkKDaPHaaIV74DWhKs8W{bIxS zF`Twq^r6^9m1;juEY{Zcj<;;k z<@kTMQmJgnlUNAfMN!1AR4N-_ttcj1Gt8zG{vXTjaW z!CqGP=jHV=_WnT;c`Of7Aw_P$^MO1mBDshyB9ArOX6Cb6GV>3t%D$F$_mPFj4R~7i zt67UZK0dwyz-!h+{@(HpBJz2QRHjq$Jp9Qq`fS(wyA^4SOoEUXEurtvf=rez*@mxW zGjk?+lbHE_OT%YdZi2Oj*}LpC1@aWRfjq@_M62#0+Pdlx z&|2?AJq5j8-xJ6>izVvGtpDjSzVKcWo0+e2xFVJS%;$C_lzGywgA@J%V7LeeCiIGl ziHY;gnFVh;>NiP5U&@sbGw<;9*-Om)a}oJ)u7m=hTCHwE>vq6pcd>|kCJHf=?$s|H&`_@03A`))VuK!yQ4VjjRW>N|X!w^PrV m-=@tyk1+EgBHB|#VgCyk>1X%x1qfIG0000 Date: Sun, 18 Sep 2016 14:17:54 +0800 Subject: [PATCH 08/35] when _onScroll(e) called, if e.nativeEvent.layoutMeasurement.width === 0, return --- .DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/.DS_Store b/.DS_Store index cc7475e8c21667e3501f24600110552b616e964b..a5cfa2bc2311f4a49556565e6973b8202b2cf076 100644 GIT binary patch delta 236 zcmZoMXfc=|#>B!ku~2NHo+2ab#(>?7ix)66F|tnPVbb$SDlaZb%E?b+U|{%}RFIQd zTw-8wlaYy;g_Vt+gOiJ!o12SUK#(goI3vG2xFoTpwAd-JC>qSmOi4|GvI7!JGLjM} zFJ(#!=iubzgXF;P}{X= z@sg#>majN`6lgyXFfu}D24N@-qmFIXU^>CHnVo~51L&8{6Pdp=Pv#eKB)qu~2NHo+2a5#(>?7j4YFRSoAgrvTkGA*dWflnVo~51E^%PAjfy+ V$^0UY91K9f$iTp|IYML&GXOc?4>kY* diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 12624b5..6397e7e 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -178,6 +178,10 @@ export default class FullScreenContainer extends React.Component { _onScroll(e) { const event = e.nativeEvent; const layoutWidth = event.layoutMeasurement.width; + if (layoutWidth === 0) { + return; + }; + const newIndex = Math.floor((event.contentOffset.x + 0.5 * layoutWidth) / layoutWidth); this._onPageSelected(newIndex); From 9866a87250e2a51fd6da4bacb28a3df2387ddada Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sun, 18 Sep 2016 17:40:04 +0800 Subject: [PATCH 09/35] add _triggerTopBarStatus function to set the currentIndex and currentMedia state --- lib/FullScreenContainer.js | 13 ++++++++++++- lib/index.js | 24 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 6397e7e..6ca1d6f 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -134,6 +134,17 @@ export default class FullScreenContainer extends React.Component { } } + _triggerTopBarStatus() { + const triggerTopBarStatus = this.props.triggerTopBarStatus; + + // action behaviour must be implemented by the client + // so, call the client method or simply ignore this event + if (triggerTopBarStatus) { + const { currentMedia, currentIndex } = this.state; + triggerTopBarStatus(currentMedia, currentIndex); + } + } + _toggleControls() { const { alwaysShowControls, toggleTopBar } = this.props; @@ -181,7 +192,7 @@ export default class FullScreenContainer extends React.Component { if (layoutWidth === 0) { return; }; - + const newIndex = Math.floor((event.contentOffset.x + 0.5 * layoutWidth) / layoutWidth); this._onPageSelected(newIndex); diff --git a/lib/index.js b/lib/index.js index 8cb9bef..90df1db 100644 --- a/lib/index.js +++ b/lib/index.js @@ -106,15 +106,17 @@ export default class PhotoBrowser extends React.Component { this._onMediaSelection = this._onMediaSelection.bind(this); this._updateTitle = this._updateTitle.bind(this); this._toggleTopBar = this._toggleTopBar.bind(this); + this._triggerTopBarStatus = this._triggerTopBarStatus.bind(this); + this._onTopRight = this._onTopRight.bind(this); const { mediaList, startOnGrid, initialIndex } = props; - this.state = { dataSource: this._createDataSource(mediaList), mediaList, isFullScreen: !startOnGrid, fullScreenAnim: new Animated.Value(startOnGrid ? 0 : 1), currentIndex: initialIndex, + currentMedia: mediaList[props.initialIndex], displayTopBar: true, }; } @@ -171,6 +173,12 @@ export default class PhotoBrowser extends React.Component { displayTopBar: displayed, }); } + _triggerTopBarStatus(currentMedia, currentIndex) { + this.setState({ + currentIndex: currentIndex, + currentMedia: currentMedia, + }); + } _toggleFullScreen(display: boolean) { this.setState({ @@ -185,6 +193,17 @@ export default class PhotoBrowser extends React.Component { ).start(); } + _onTopRight() { + const onTopRight = this.props.onTopRight; + + // action behaviour must be implemented by the client + // so, call the client method or simply ignore this event + if (onTopRight) { + const { currentMedia, currentIndex } = this.state; + onTopRight(currentMedia, currentIndex); + } + } + render() { const { alwaysShowControls, @@ -253,6 +272,7 @@ export default class PhotoBrowser extends React.Component { onGridButtonTap={this._onGridButtonTap} updateTitle={this._updateTitle} toggleTopBar={this._toggleTopBar} + triggerTopBarStatus={this._triggerTopBarStatus} /> ); } @@ -269,7 +289,7 @@ export default class PhotoBrowser extends React.Component { displayed={displayTopBar} title={isFullScreen ? title : `${mediaList.length} photos`} onBack={onBack} - onTopRight={onTopRight} + onTopRight={this._onTopRight} topRightView={topRightView} topRightStyle={topRightStyle} /> From af0d10e5c695b5270b5f2b5ee8320c37f6dddc3c Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sun, 18 Sep 2016 17:46:09 +0800 Subject: [PATCH 10/35] add _triggerTopBarStatus when _updatePageIndex(index) --- lib/FullScreenContainer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 6ca1d6f..81d6518 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -114,6 +114,7 @@ export default class FullScreenContainer extends React.Component { currentIndex: index, currentMedia: this.props.mediaList[index], }, () => { + this._triggerTopBarStatus(); this._triggerPhotoLoad(index); const newTitle = `${index + 1} of ${this.props.dataSource.getRowCount()}`; From 01621e71cd080be4c204312c670246fea83f02dc Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sun, 18 Sep 2016 20:04:28 +0800 Subject: [PATCH 11/35] create a new branch 'createResponder' for gesture responder --- .DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 1 + 2 files changed, 1 insertion(+) diff --git a/.DS_Store b/.DS_Store index a5cfa2bc2311f4a49556565e6973b8202b2cf076..04b6df976c9307ad34a49112b655fb60b9e34d01 100644 GIT binary patch delta 21 ccmZoMXffE}$i`u8V5Fm9WMH(}lWn&k06=^Ns{jB1 delta 21 ccmZoMXffE}$i`u2WUixNWMsVAlWn&k06_)?xBvhE diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 81d6518..1b81875 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -264,6 +264,7 @@ export default class FullScreenContainer extends React.Component { ref={scrollView => this.scrollView = scrollView} dataSource={dataSource} renderRow={this._renderRow} + scrollEnabled={false} onScroll={this._onScroll} horizontal pagingEnabled From 0c69fedee6ad51965256b6c959679bf3cb81fb50 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 20 Sep 2016 09:52:59 +0800 Subject: [PATCH 12/35] use Gallery success --- .DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 40 +++++- lib/Gallery.js | 259 +++++++++++++++++++++++++++++++++++++ lib/index.js | 2 + lib/media/Photo.js | 4 + package.json | 4 +- 6 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 lib/Gallery.js diff --git a/.DS_Store b/.DS_Store index 04b6df976c9307ad34a49112b655fb60b9e34d01..1e31f6b1555bc857e193333cc93c93c609a2c54b 100644 GIT binary patch delta 36 scmZoMXffDO$U51DWdpmhfsTT)q50(BEbf~pvXwDTY*5c21d0y3f1Q32098R#%8s(9GsjSvf5r@NtJDrS8qRj this.photoRefs[rowID] = ref} + ref={ref => { + this.photoRefs[rowID] = ref; + if (ref) { + const transformableImage = ref.getTransformableImage(); + gallery.setImageRef(rowID, transformableImage); + }; + }} lazyLoad useCircleProgress={useCircleProgress} uri={media.photo} @@ -245,7 +264,21 @@ export default class FullScreenContainer extends React.Component { } _renderScrollableContent() { - const { dataSource, mediaList } = this.props; + const { dataSource, mediaList, useGallery } = this.props; + if (useGallery) { + return ( + { + return this._renderRow(pageData, 0, pageId, gallery); + }} + /> + ); + }; if (Platform.OS === 'android') { return ( @@ -264,7 +297,6 @@ export default class FullScreenContainer extends React.Component { ref={scrollView => this.scrollView = scrollView} dataSource={dataSource} renderRow={this._renderRow} - scrollEnabled={false} onScroll={this._onScroll} horizontal pagingEnabled diff --git a/lib/Gallery.js b/lib/Gallery.js new file mode 100644 index 0000000..d879a4b --- /dev/null +++ b/lib/Gallery.js @@ -0,0 +1,259 @@ +import React, { Component, PropTypes } from 'react'; +import { + View +} from 'react-native'; + +import Image from 'react-native-transformable-image'; +import ViewPager from '@ldn0x7dc/react-native-view-pager'; +import {createResponder} from 'react-native-gesture-responder'; + + +export default class Gallery extends Component { + + static propTypes = { + ...View.propTypes, + images: PropTypes.array, + + initialPage: PropTypes.number, + pageMargin: PropTypes.number, + onPageSelected: PropTypes.func, + onPageScrollStateChanged: PropTypes.func, + onPageScroll: PropTypes.func, + + onSingleTapConfirmed: PropTypes.func, + onGalleryStateChanged: PropTypes.func + }; + + imageRefs = new Map(); + activeResponder = undefined; + firstMove = true; + currentPage = 0; + pageCount = 0; + gestureResponder = undefined; + + constructor(props) { + super(props); + } + + componentWillMount() { + function onResponderReleaseOrTerminate(evt, gestureState) { + if (this.activeResponder) { + if (this.activeResponder === this.viewPagerResponder + && !this.shouldScrollViewPager(evt, gestureState) + && Math.abs(gestureState.vx) > 0.5) { + this.activeResponder.onEnd(evt, gestureState, true); + this.getViewPagerInstance().flingToPage(this.currentPage, gestureState.vx); + } else { + this.activeResponder.onEnd(evt, gestureState); + } + this.activeResponder = null; + } + this.firstMove = true; + this.props.onGalleryStateChanged && this.props.onGalleryStateChanged(true); + } + + this.gestureResponder = createResponder({ + onStartShouldSetResponderCapture: (evt, gestureState) => true, + onStartShouldSetResponder: (evt, gestureState) => { + return true; + }, + onResponderGrant: (evt, gestureState) => { + this.activeImageResponder(evt, gestureState); + }, + onResponderMove: (evt, gestureState) => { + if (this.firstMove) { + this.firstMove = false; + if (this.shouldScrollViewPager(evt, gestureState)) { + this.activeViewPagerResponder(evt, gestureState); + } + this.props.onGalleryStateChanged && this.props.onGalleryStateChanged(false); + } + if (this.activeResponder === this.viewPagerResponder) { + const dx = gestureState.moveX - gestureState.previousMoveX; + const offset = this.getViewPagerInstance().getScrollOffsetFromCurrentPage(); + if (dx > 0 && offset > 0 && !this.shouldScrollViewPager(evt, gestureState)) { + if (dx > offset) { // active image responder + this.getViewPagerInstance().scrollByOffset(offset); + gestureState.moveX -= offset; + this.activeImageResponder(evt, gestureState); + } + } else if (dx < 0 && offset < 0 && !this.shouldScrollViewPager(evt, gestureState)) { + if (dx < offset) { // active image responder + this.getViewPagerInstance().scrollByOffset(offset); + gestureState.moveX -= offset; + this.activeImageResponder(evt, gestureState); + } + } + } + this.activeResponder.onMove(evt, gestureState); + }, + onResponderRelease: onResponderReleaseOrTerminate.bind(this), + onResponderTerminate: onResponderReleaseOrTerminate.bind(this), + onResponderTerminationRequest: (evt, gestureState) => false, //Do not allow parent view to intercept gesture + onResponderSingleTapConfirmed: (evt, gestureState) => { + this.props.onSingleTapConfirmed && this.props.onSingleTapConfirmed(this.currentPage); + } + }); + + this.viewPagerResponder = { + onStart: (evt, gestureState) => { + this.getViewPagerInstance().onResponderGrant(evt, gestureState); + }, + onMove: (evt, gestureState) => { + this.getViewPagerInstance().onResponderMove(evt, gestureState); + }, + onEnd: (evt, gestureState, disableSettle) => { + this.getViewPagerInstance().onResponderRelease(evt, gestureState, disableSettle); + } + } + + this.imageResponder = { + onStart: ((evt, gestureState) => { + this.getCurrentImageTransformer().onResponderGrant(evt, gestureState); + }), + onMove: (evt, gestureState) => { + this.getCurrentImageTransformer().onResponderMove(evt, gestureState); + }, + onEnd: (evt, gestureState) => { + this.getCurrentImageTransformer().onResponderRelease(evt, gestureState); + } + } + } + + shouldScrollViewPager(evt, gestureState) { + if (gestureState.numberActiveTouches > 1) { + return false; + } + const viewTransformer = this.getCurrentImageTransformer(); + const space = viewTransformer.getAvailableTranslateSpace(); + const dx = gestureState.moveX - gestureState.previousMoveX; + + if (dx > 0 && space.left <= 0 && this.currentPage > 0) { + return true; + } + if (dx < 0 && space.right <= 0 && this.currentPage < this.pageCount - 1) { + return true; + } + return false; + } + + activeImageResponder(evt, gestureState) { + if (this.activeResponder !== this.imageResponder) { + if (this.activeResponder === this.viewPagerResponder) { + this.viewPagerResponder.onEnd(evt, gestureState, true); //pass true to disable ViewPager settle + } + this.activeResponder = this.imageResponder; + this.imageResponder.onStart(evt, gestureState); + } + } + + activeViewPagerResponder(evt, gestureState) { + if (this.activeResponder !== this.viewPagerResponder) { + if (this.activeResponder === this.imageResponder) { + this.imageResponder.onEnd(evt, gestureState); + } + this.activeResponder = this.viewPagerResponder; + this.viewPagerResponder.onStart(evt, gestureState) + } + } + + getImageTransformer(page) { + if (page >= 0 && page < this.pageCount) { + let ref = this.imageRefs.get(page + ''); + if (ref) { + return ref.getViewTransformerInstance(); + } + } + } + + getCurrentImageTransformer() { + return this.getImageTransformer(this.currentPage); + } + + getViewPagerInstance() { + return this.refs['galleryViewPager']; + } + + render() { + let gestureResponder = this.gestureResponder; + + let images = this.props.images; + if (!images) { + images = []; + } + this.pageCount = images.length; + + if (this.pageCount <= 0) { + gestureResponder = {}; + } + + return ( + + ); + } + + onPageSelected(page) { + this.currentPage = page; + this.props.onPageSelected && this.props.onPageSelected(page); + } + + onPageScrollStateChanged(state) { + if (state === 'idle') { + this.resetHistoryImageTransform(); + } + this.props.onPageScrollStateChanged && this.props.onPageScrollStateChanged(state); + } + + onPageScroll(e) { + this.props.onPageScroll && this.props.onPageScroll(e); + } + + setImageRef(pageId, ref) { + this.imageRefs.set(pageId, ref); + } + + renderPage(pageData, pageId, layout) { + const { onViewTransformed, onTransformGestureReleased, customItem, ...other } = this.props; + if (customItem && typeof customItem === 'function') { + return customItem(pageData, pageId, layout, this); + }; + return ( + { + onViewTransformed && onViewTransformed(transform, pageId); + }).bind(this)} + onTransformGestureReleased={((transform) => { + onTransformGestureReleased && onTransformGestureReleased(transform, pageId); + }).bind(this)} + ref={((ref) => { + this.imageRefs.set(pageId, ref); + }).bind(this)} + key={'innerImage#' + pageId} + style={{width: layout.width, height: layout.height}} + source={{uri: pageData}}/> + ); + } + + resetHistoryImageTransform() { + let transformer = this.getImageTransformer(this.currentPage + 1); + if (transformer) { + transformer.forceUpdateTransform({scale: 1, translateX: 0, translateY: 0}); + } + + transformer = this.getImageTransformer(this.currentPage - 1); + if (transformer) { + transformer.forceUpdateTransform({scale: 1, translateX: 0, translateY: 0}); + } + } +} diff --git a/lib/index.js b/lib/index.js index 90df1db..f6d49fb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -218,6 +218,7 @@ export default class PhotoBrowser extends React.Component { onTopRight, topRightView, topRightStyle, + useGallery, } = this.props; const { dataSource, @@ -273,6 +274,7 @@ export default class PhotoBrowser extends React.Component { updateTitle={this._updateTitle} toggleTopBar={this._toggleTopBar} triggerTopBarStatus={this._triggerTopBarStatus} + useGallery={useGallery} /> ); } diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 9ecd16c..59be8c8 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -124,6 +124,10 @@ export default class Photo extends Component { } } + getTransformableImage() { + return this.transformableImage; + } + _onProgress(event) { const progress = event.nativeEvent.loaded / event.nativeEvent.total; if (!this.props.thumbnail && progress !== this.state.progress) { diff --git a/package.json b/package.json index ca53de7..52b9ef6 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "homepage": "https://github.com/halilb/react-native-photo-browser#readme", "dependencies": { "react-native-progress": "^3.0.0", - "react-native-transformable-image": "0.0.18" + "react-native-transformable-image": "0.0.18", + "@ldn0x7dc/react-native-view-pager": "0.0.9", + "react-native-gesture-responder": "0.1.1" } } From edd052f8b6a85d4ac35ed88335e9662788d6225d Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 20 Sep 2016 15:36:49 +0800 Subject: [PATCH 13/35] fix bug Gallery initialPage not working --- lib/FullScreenContainer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 57678cc..b17424b 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -264,14 +264,14 @@ export default class FullScreenContainer extends React.Component { } _renderScrollableContent() { - const { dataSource, mediaList, useGallery } = this.props; + const { dataSource, mediaList, useGallery, initialIndex } = this.props; if (useGallery) { return ( { return this._renderRow(pageData, 0, pageId, gallery); From 34202d62d8f33a4524115855260c24ac0c78b04e Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 10:26:24 +0800 Subject: [PATCH 14/35] when prevProps.mediaList.length !== this.props.mediaList.length , this._updatePageIndex(this.props.initialIndex); --- .DS_Store | Bin 6148 -> 6148 bytes lib/FullScreenContainer.js | 15 +++++++++++++-- lib/Gallery.js | 4 ++++ lib/index.js | 9 ++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.DS_Store b/.DS_Store index 1e31f6b1555bc857e193333cc93c93c609a2c54b..2ad989e2647e2460f1b01a766513d4f0c020fac7 100644 GIT binary patch delta 24 fcmZoMXffEJ$i{ADq@!SLWH|XZi~Ht$wyA;uR{;k! delta 24 fcmZoMXffEJ$i{ALprc@HXg>Kji~Ht$wyA;uS0o2G diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index b17424b..f2ffb42 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -95,6 +95,12 @@ export default class FullScreenContainer extends React.Component { this.openPage(this.state.currentIndex, false); } + componentDidUpdate(prevProps, prevState) { + if (prevProps.mediaList.length !== this.props.mediaList.length) { + this._updatePageIndex(this.props.initialIndex); + } + } + openPage(index, animated) { if (!this.scrollView) { this._updatePageIndex(index); @@ -122,11 +128,15 @@ export default class FullScreenContainer extends React.Component { this._triggerTopBarStatus(); this._triggerPhotoLoad(index); - const newTitle = `${index + 1} of ${this.props.dataSource.getRowCount()}`; - this.props.updateTitle(newTitle); + this._updateTitle(index); }); } + _updateTitle(index) { + const newTitle = `${index + 1} of ${this.props.dataSource.getRowCount()}`; + this.props.updateTitle(newTitle); + } + _triggerPhotoLoad(index) { const photo = this.photoRefs[index]; if (photo) { @@ -268,6 +278,7 @@ export default class FullScreenContainer extends React.Component { if (useGallery) { return ( this.gallery = ref} style={{flex: 1, backgroundColor: 'black'}} onPageSelected={this._onGalleryPageSelected} onSingleTapConfirmed={this._onSingleTapConfirmed} diff --git a/lib/Gallery.js b/lib/Gallery.js index d879a4b..af59990 100644 --- a/lib/Gallery.js +++ b/lib/Gallery.js @@ -222,6 +222,10 @@ export default class Gallery extends Component { this.imageRefs.set(pageId, ref); } + deleteImageRef(pageId) { + this.imageRefs.delete(`${pageId}`); + } + renderPage(pageData, pageId, layout) { const { onViewTransformed, onTransformGestureReleased, customItem, ...other } = this.props; if (customItem && typeof customItem === 'function') { diff --git a/lib/index.js b/lib/index.js index f6d49fb..fb472bc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -195,12 +195,13 @@ export default class PhotoBrowser extends React.Component { _onTopRight() { const onTopRight = this.props.onTopRight; + const gallery = this.fullScreenContainer && this.fullScreenContainer.gallery; // action behaviour must be implemented by the client // so, call the client method or simply ignore this event if (onTopRight) { const { currentMedia, currentIndex } = this.state; - onTopRight(currentMedia, currentIndex); + onTopRight(currentMedia, currentIndex, gallery); } } @@ -219,6 +220,7 @@ export default class PhotoBrowser extends React.Component { topRightView, topRightStyle, useGallery, + initialIndex, } = this.props; const { dataSource, @@ -258,10 +260,11 @@ export default class PhotoBrowser extends React.Component { fullScreenContainer = ( this.fullScreenContainer = ref} dataSource={dataSource} mediaList={mediaList} - initialIndex={currentIndex} + initialIndex={initialIndex} alwaysShowControls={alwaysShowControls} displayNavArrows={displayNavArrows} displaySelectionButtons={displaySelectionButtons} From 96f0ee231f69d0cb7b3e4800429776d93acc5079 Mon Sep 17 00:00:00 2001 From: kstain <1353990812@qq.com> Date: Wed, 21 Sep 2016 10:51:29 +0800 Subject: [PATCH 15/35] Update README.md --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 01fabbe..70a44fc 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,79 @@ const media = { }; ``` +### Usage +```js +_onTopRight = (currentMedia, currentIndex, gallery) => { + console.log('currentMedia:' + currentMedia + 'currentIndex:' + currentIndex); + gallery && gallery.deleteImageRef(currentIndex); + let initialIndex = Math.max(0, currentIndex - 1); + let images = this.state.images; + if (images.length > 1) { + images.splice(currentIndex, 1); // 删掉选中的照片 + // update state + this.setState({ + imageDataSource: this.state.imageDataSource.cloneWithRows(images), + images: images, + configPhotoBrowser: { + ...this.state.configPhotoBrowser, + initialIndex: initialIndex, + media: images.slice(0, images.length - 1), + }, + }) + } else { + this.setState({ + imageDataSource: this.state.imageDataSource.cloneWithRows(images), + images: images, + configPhotoBrowser: { + ...this.state.configPhotoBrowser, + initialIndex: initialIndex, + media: images.slice(0, images.length - 1), + }, + }) + } + + } + + _renderModalPhotoBrowser = () => { + const { + media, + initialIndex, + displayNavArrows, + displayActionButton, + displaySelectionButtons, + startOnGrid, + enableGrid, + } = this.state.configPhotoBrowser; + + return ( + + + this.setState({showPhotoBrowser: false})} + mediaList={media} + initialIndex={initialIndex} + displayNavArrows={displayNavArrows} + displaySelectionButtons={displaySelectionButtons} + displayActionButton={displayActionButton} + startOnGrid={startOnGrid} + enableGrid={enableGrid} + useCircleProgress + onSelectionChanged={this._onSelectionChanged} + onActionButton={this._onActionButton} + onTopRight={this._onTopRight} + topRightView={this._renderTopRightView()} + topRightStyle={{overflow: 'hidden'}} + useGallery={true} + /> + + + ); + } +``` ### Progress Component @@ -70,7 +143,7 @@ Follow those steps to run the example: - [x] Android support - [ ] Improve performance for bigger collections - [ ] Video support -- [ ] Photo zoom +- [x] Photo zoom - [ ] Zooming photos to fill the screen ### Licence From f20c9d47c1df95e3a8f45e442bd8394cf24d2aa1 Mon Sep 17 00:00:00 2001 From: kstain <1353990812@qq.com> Date: Wed, 21 Sep 2016 13:19:58 +0800 Subject: [PATCH 16/35] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 70a44fc..bf78522 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ The component has both iOS and Android support. ![](screenshots/screenshot-2.png) ### Installation -```npm install react-native-photo-browser --save``` +```npm install react-native-photo-browser --save``` + +or ```npm install react-native-photo-browser@https://github.com/ksti/react-native-photo-browser.git --save``` ### Properties From ce6844b68b251d77fff862998bd4d1a9b34523b8 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 15:05:22 +0800 Subject: [PATCH 17/35] onTopRight call back isFullScreen and mediaList --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index fb472bc..de630e8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -200,8 +200,8 @@ export default class PhotoBrowser extends React.Component { // action behaviour must be implemented by the client // so, call the client method or simply ignore this event if (onTopRight) { - const { currentMedia, currentIndex } = this.state; - onTopRight(currentMedia, currentIndex, gallery); + const { currentMedia, currentIndex, isFullScreen, mediaList } = this.state; + onTopRight(currentMedia, currentIndex, gallery, isFullScreen, mediaList); } } From a2a1922b910084edd65435e9865ca216829dfabd Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 15:23:17 +0800 Subject: [PATCH 18/35] add the missing refs: this.refs.fullScreenContainer --> this.fullScreenContainer --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index de630e8..f58958b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -137,7 +137,7 @@ export default class PhotoBrowser extends React.Component { } _onGridPhotoTap(index) { - this.refs.fullScreenContainer.openPage(index, false); + this.fullScreenContainer.openPage(index, false); this._toggleFullScreen(true); } From 8c5fb2c66bdedc0b01c404729818444807c31262 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 15:52:31 +0800 Subject: [PATCH 19/35] update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52b9ef6..54f61de 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "react-native-progress": "^3.0.0", "react-native-transformable-image": "0.0.18", - "@ldn0x7dc/react-native-view-pager": "0.0.9", + "@ksti/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", "react-native-gesture-responder": "0.1.1" } } From 484d6af1d924d38afaec43c466523bf6b86bb121 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 15:59:05 +0800 Subject: [PATCH 20/35] update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54f61de..6835bd1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "react-native-progress": "^3.0.0", "react-native-transformable-image": "0.0.18", - "@ksti/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", + "@ldn0x7dc/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", "react-native-gesture-responder": "0.1.1" } } From eb517889de0a4a76ca4e8b8fbd345e257bdd7a55 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 16:23:36 +0800 Subject: [PATCH 21/35] for test --- .DS_Store | Bin 6148 -> 6148 bytes lib/Gallery.js | 3 ++- package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.DS_Store b/.DS_Store index 2ad989e2647e2460f1b01a766513d4f0c020fac7..6cb9d4cc3f17881efef552409171fde133ff8391 100644 GIT binary patch delta 24 fcmZoMXffEJz{YN5Y^kGQY&iKBi^t}CwyA;uS9AwE delta 25 gcmZoMXffEJz{X){WTc~DY-Bk3H;en`e732A09=O$WdHyG diff --git a/lib/Gallery.js b/lib/Gallery.js index af59990..81785ee 100644 --- a/lib/Gallery.js +++ b/lib/Gallery.js @@ -4,7 +4,8 @@ import { } from 'react-native'; import Image from 'react-native-transformable-image'; -import ViewPager from '@ldn0x7dc/react-native-view-pager'; +// import ViewPager from '@ldn0x7dc/react-native-view-pager'; +import ViewPager from '@ksti/react-native-view-pager'; import {createResponder} from 'react-native-gesture-responder'; diff --git a/package.json b/package.json index 6835bd1..54f61de 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "react-native-progress": "^3.0.0", "react-native-transformable-image": "0.0.18", - "@ldn0x7dc/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", + "@ksti/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", "react-native-gesture-responder": "0.1.1" } } From fc8b550169948c9ee4f42adcd0f431da286d1ce5 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 16:28:02 +0800 Subject: [PATCH 22/35] test failed, backup. --- lib/Gallery.js | 3 +-- package.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Gallery.js b/lib/Gallery.js index 81785ee..af59990 100644 --- a/lib/Gallery.js +++ b/lib/Gallery.js @@ -4,8 +4,7 @@ import { } from 'react-native'; import Image from 'react-native-transformable-image'; -// import ViewPager from '@ldn0x7dc/react-native-view-pager'; -import ViewPager from '@ksti/react-native-view-pager'; +import ViewPager from '@ldn0x7dc/react-native-view-pager'; import {createResponder} from 'react-native-gesture-responder'; diff --git a/package.json b/package.json index 54f61de..6835bd1 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "react-native-progress": "^3.0.0", "react-native-transformable-image": "0.0.18", - "@ksti/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", + "@ldn0x7dc/react-native-view-pager": "https://github.com/ksti/react-native-view-pager", "react-native-gesture-responder": "0.1.1" } } From 427494d67fa4e7a5e15cce11c4dce332ad7a27b6 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Wed, 21 Sep 2016 17:47:12 +0800 Subject: [PATCH 23/35] when update page index such as form openPage function calling, should rerender Gallery for reasons that you want to scroll to some other page using 'currentIndex' --- lib/FullScreenContainer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index f2ffb42..522b4f3 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -282,7 +282,8 @@ export default class FullScreenContainer extends React.Component { style={{flex: 1, backgroundColor: 'black'}} onPageSelected={this._onGalleryPageSelected} onSingleTapConfirmed={this._onSingleTapConfirmed} - initialPage={initialIndex} + // initialPage={initialIndex} + initialPage={this.state.currentIndex} images={mediaList} customItem={(pageData, pageId, layout, gallery) => { return this._renderRow(pageData, 0, pageId, gallery); From 4cb327384db5c7f2026470b6952dc8c7f0d5d47a Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Mon, 26 Sep 2016 15:46:11 +0800 Subject: [PATCH 24/35] load(force) --- lib/FullScreenContainer.js | 16 +++++++++------- lib/media/Photo.js | 10 ++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 522b4f3..130b155 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -67,6 +67,7 @@ export default class FullScreenContainer extends React.Component { constructor(props, context) { super(props, context); + this.mediaList = new Array().concat(props.mediaList); this._renderRow = this._renderRow.bind(this); this._toggleControls = this._toggleControls.bind(this); @@ -95,9 +96,10 @@ export default class FullScreenContainer extends React.Component { this.openPage(this.state.currentIndex, false); } - componentDidUpdate(prevProps, prevState) { - if (prevProps.mediaList.length !== this.props.mediaList.length) { - this._updatePageIndex(this.props.initialIndex); + componentWillReceiveProps(nextProps) { + if (nextProps.mediaList.length !== this.mediaList.length) { + this.mediaList = new Array().concat(nextProps.mediaList); + this._updatePageIndex(nextProps.initialIndex, true); } } @@ -120,13 +122,13 @@ export default class FullScreenContainer extends React.Component { this._updatePageIndex(index); } - _updatePageIndex(index) { + _updatePageIndex(index, force) { this.setState({ currentIndex: index, currentMedia: this.props.mediaList[index], }, () => { this._triggerTopBarStatus(); - this._triggerPhotoLoad(index); + this._triggerPhotoLoad(index, force); this._updateTitle(index); }); @@ -137,10 +139,10 @@ export default class FullScreenContainer extends React.Component { this.props.updateTitle(newTitle); } - _triggerPhotoLoad(index) { + _triggerPhotoLoad(index, force) { const photo = this.photoRefs[index]; if (photo) { - photo.load(); + photo.load(force); } else { // HACK: photo might be undefined when user taps a photo from gridview // that hasn't been rendered yet. diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 59be8c8..13c5a8e 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -108,7 +108,7 @@ export default class Photo extends Component { }; } - load() { + load(force) { if (this.transformableImage) { const viewTransformer = this.transformableImage.getViewTransformerInstance(); viewTransformer && viewTransformer.setState({ @@ -117,10 +117,16 @@ export default class Photo extends Component { translateY: 0, }); }; - if (!this.state.uri) { + if (force === true) { this.setState({ uri: this.props.uri, }); + } else { + if (!this.state.uri) { + this.setState({ + uri: this.props.uri, + }); + } } } From 83287cebbb9b1a61adcefc9d34e63c374b072f3c Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Mon, 26 Sep 2016 16:31:53 +0800 Subject: [PATCH 25/35] _onPageSelected force load --- lib/FullScreenContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 130b155..e823f56 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -230,7 +230,7 @@ export default class FullScreenContainer extends React.Component { } if (currentIndex !== newIndex) { - this._updatePageIndex(newIndex); + this._updatePageIndex(newIndex, true); if (this.state.controlsDisplayed) { this._toggleControls(); From 75da655797dcd8a0fc6df7754b13b6724d4b2c5a Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sat, 8 Oct 2016 12:47:37 +0800 Subject: [PATCH 26/35] should confirm whether using gallery --- lib/FullScreenContainer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index e823f56..78c3918 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -257,7 +257,9 @@ export default class FullScreenContainer extends React.Component { this.photoRefs[rowID] = ref; if (ref) { const transformableImage = ref.getTransformableImage(); - gallery.setImageRef(rowID, transformableImage); + if (gallery && gallery.setImageRef) { + gallery.setImageRef(rowID, transformableImage); + }; }; }} lazyLoad From 18bc9bf3a06cd68ab389080d5b484647e5474edb Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sat, 8 Oct 2016 13:27:48 +0800 Subject: [PATCH 27/35] update Example --- Example/PhotoBrowserExample.js | 2 ++ Example/ios/PhotoBrowserExample/Info.plist | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Example/PhotoBrowserExample.js b/Example/PhotoBrowserExample.js index 85b09db..c922ee7 100644 --- a/Example/PhotoBrowserExample.js +++ b/Example/PhotoBrowserExample.js @@ -50,6 +50,7 @@ const EXAMPLES = [ title: 'Library photos', description: 'showing grid first, custom action method', startOnGrid: true, + displaySelectionButtons: true, displayActionButton: true, }, ]; @@ -166,6 +167,7 @@ export default class PhotoBrowserExample extends Component { startOnGrid={startOnGrid} enableGrid={enableGrid} useCircleProgress + useGallery={true} onSelectionChanged={this._onSelectionChanged} onActionButton={this._onActionButton} onTopRight={() => console.log('on top right click')} diff --git a/Example/ios/PhotoBrowserExample/Info.plist b/Example/ios/PhotoBrowserExample/Info.plist index 91963b2..882b2d0 100644 --- a/Example/ios/PhotoBrowserExample/Info.plist +++ b/Example/ios/PhotoBrowserExample/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion en + NSPhotoLibraryUsageDescription + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -38,11 +40,10 @@ NSLocationWhenInUseUsageDescription - NSAppTransportSecurity - - - NSAllowsArbitraryLoads - - + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + From d104f1ac5e240a0a138486ce98a3dd421f7c3519 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Tue, 1 Nov 2016 16:21:06 +0800 Subject: [PATCH 28/35] add forceLoadPhoto props --- lib/FullScreenContainer.js | 6 ++++-- lib/index.js | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 78c3918..bd50c26 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -55,6 +55,7 @@ export default class FullScreenContainer extends React.Component { enableGrid: PropTypes.bool, useCircleProgress: PropTypes.bool, onActionButton: PropTypes.func, + forceLoadPhoto: PropTypes.bool, }; static defaultProps = { @@ -84,6 +85,7 @@ export default class FullScreenContainer extends React.Component { currentIndex: props.initialIndex, currentMedia: props.mediaList[props.initialIndex], controlsDisplayed: true, + forceLoadPhoto: props.forceLoadPhoto || false, }; } @@ -99,7 +101,7 @@ export default class FullScreenContainer extends React.Component { componentWillReceiveProps(nextProps) { if (nextProps.mediaList.length !== this.mediaList.length) { this.mediaList = new Array().concat(nextProps.mediaList); - this._updatePageIndex(nextProps.initialIndex, true); + this._updatePageIndex(nextProps.initialIndex, nextProps.forceLoadPhoto || this.state.forceLoadPhoto); } } @@ -230,7 +232,7 @@ export default class FullScreenContainer extends React.Component { } if (currentIndex !== newIndex) { - this._updatePageIndex(newIndex, true); + this._updatePageIndex(newIndex, this.state.forceLoadPhoto); if (this.state.controlsDisplayed) { this._toggleControls(); diff --git a/lib/index.js b/lib/index.js index f58958b..00ca9a8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -82,6 +82,11 @@ export default class PhotoBrowser extends React.Component { * Sets images amount in grid row, default - 3 (defined in GridContainer) */ itemPerRow: PropTypes.number, + + /* + * Whether to force load photo + */ + forceLoadPhoto: PropTypes.bool, }; static defaultProps = { @@ -221,6 +226,7 @@ export default class PhotoBrowser extends React.Component { topRightStyle, useGallery, initialIndex, + forceLoadPhoto, } = this.props; const { dataSource, @@ -278,6 +284,7 @@ export default class PhotoBrowser extends React.Component { toggleTopBar={this._toggleTopBar} triggerTopBarStatus={this._triggerTopBarStatus} useGallery={useGallery} + forceLoadPhoto={forceLoadPhoto} /> ); } From bf0946d2b3f4f6ba3b4cb1f22c792881b243fd6e Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Mon, 12 Dec 2016 20:05:19 +0800 Subject: [PATCH 29/35] fix bug on rn0.39 --- lib/FullScreenContainer.js | 6 +++++- lib/index.js | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index bd50c26..94598d0 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -251,8 +251,10 @@ export default class FullScreenContainer extends React.Component { useCircleProgress, } = this.props; + const screen = Dimensions.get('window'); + return ( - + { @@ -264,6 +266,8 @@ export default class FullScreenContainer extends React.Component { }; }; }} + width={screen.width} + height={screen.height} lazyLoad useCircleProgress={useCircleProgress} uri={media.photo} diff --git a/lib/index.js b/lib/index.js index 00ca9a8..db613ba 100644 --- a/lib/index.js +++ b/lib/index.js @@ -249,7 +249,7 @@ export default class PhotoBrowser extends React.Component { height: screenHeight, marginTop: fullScreenAnim.interpolate({ inputRange: [0, 1], - outputRange: [0, screenHeight * -1 - TOOLBAR_HEIGHT], + outputRange: [0, screenHeight * -1], }), }} > @@ -291,7 +291,7 @@ export default class PhotoBrowser extends React.Component { return ( {gridContainer} {fullScreenContainer} From 0cb8b8e3a513c0eac54324c1fe2d8dc8e1b91043 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Mon, 12 Dec 2016 20:07:47 +0800 Subject: [PATCH 30/35] update Example for newest RN version --- Example/PhotoBrowserExample.js | 17 ++- Example/android/PhotoBrowserExample.iml | 19 +++ Example/android/app/app.iml | 140 +++++++++++++++++ Example/android/app/build.gradle | 63 ++++++-- Example/android/app/proguard-rules.pro | 13 +- .../android/app/src/main/AndroidManifest.xml | 1 + .../com/photobrowserexample/MainActivity.java | 98 ++++++++++-- .../photobrowserexample/MainApplication.java | 52 +++++++ Example/android/backup/build.gradle | 142 ++++++++++++++++++ Example/android/backup/proguard-rules.pro | 67 +++++++++ Example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- Example/ios/PhotoBrowserExample/AppDelegate.m | 8 + Example/package.json | 4 +- 14 files changed, 589 insertions(+), 40 deletions(-) create mode 100644 Example/android/PhotoBrowserExample.iml create mode 100644 Example/android/app/app.iml create mode 100644 Example/android/app/src/main/java/com/photobrowserexample/MainApplication.java create mode 100644 Example/android/backup/build.gradle create mode 100644 Example/android/backup/proguard-rules.pro diff --git a/Example/PhotoBrowserExample.js b/Example/PhotoBrowserExample.js index c922ee7..dc612ad 100644 --- a/Example/PhotoBrowserExample.js +++ b/Example/PhotoBrowserExample.js @@ -25,7 +25,8 @@ const EXAMPLES = [ description: 'with caption, no grid button', enableGrid: false, media: [{ - photo: 'http://farm3.static.flickr.com/2667/4072710001_f36316ddc7_b.jpg', + // photo: 'http://farm3.static.flickr.com/2667/4072710001_f36316ddc7_b.jpg', + photo: 'http://sanantoniotourist.net/wp-content/uploads/2013/07/100_1922.jpg', caption: 'Grotto of the Madonna', }], }, { @@ -34,15 +35,23 @@ const EXAMPLES = [ displayNavArrows: true, displayActionButton: true, media: [{ - photo: 'http://farm3.static.flickr.com/2667/4072710001_f36316ddc7_b.jpg', + // photo: 'http://farm3.static.flickr.com/2667/4072710001_f36316ddc7_b.jpg', + photo: 'http://sanantoniotourist.net/wp-content/uploads/2013/07/100_1922.jpg', selected: true, caption: 'Grotto of the Madonna', }, { photo: require('./media/broadchurch_thumbnail.png'), caption: 'Broadchurch Scene', }, { - photo: 'http://farm3.static.flickr.com/2449/4052876281_6e068ac860_b.jpg', - thumb: 'http://farm3.static.flickr.com/2449/4052876281_6e068ac860_q.jpg', + photo: 'https://a1.dspncdn.com/media/692x/9c/ed/1b/9ced1b427a167ed38b0b66fe3c62f2ae.jpg', + thumb: 'https://a1.dspncdn.com/media/206x/9c/ed/1b/9ced1b427a167ed38b0b66fe3c62f2ae.jpg', + selected: false, + caption: 'rose && fire', + }, { + // photo: 'http://farm3.static.flickr.com/2449/4052876281_6e068ac860_b.jpg', + // thumb: 'http://farm3.static.flickr.com/2449/4052876281_6e068ac860_q.jpg', + photo: 'https://a1.dspncdn.com/media/692x/64/9c/53/649c5331e0f1fb645fa8d25a4ec0e53c.jpg', + thumb: 'https://a1.dspncdn.com/media/206x/64/9c/53/649c5331e0f1fb645fa8d25a4ec0e53c.jpg', selected: false, caption: 'Beautiful Eyes', }], diff --git a/Example/android/PhotoBrowserExample.iml b/Example/android/PhotoBrowserExample.iml new file mode 100644 index 0000000..eeca891 --- /dev/null +++ b/Example/android/PhotoBrowserExample.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Example/android/app/app.iml b/Example/android/app/app.iml new file mode 100644 index 0000000..5293d7b --- /dev/null +++ b/Example/android/app/app.iml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Example/android/app/build.gradle b/Example/android/app/build.gradle index 06d6f6e..9aef690 100644 --- a/Example/android/app/build.gradle +++ b/Example/android/app/build.gradle @@ -9,7 +9,7 @@ import com.android.build.OutputFile * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the * bundle directly from the development server. Below you can see all the possible configurations * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "react.gradle"` line. + * `apply from: "../../node_modules/react-native/react.gradle"` line. * * project.ext.react = [ * // the name of the generated asset file containing your JS bundle @@ -55,11 +55,17 @@ import com.android.build.OutputFile * // date; if you have any other folders that you want to ignore for performance reasons (gradle * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"] + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"] + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] * ] */ -apply from: "react.gradle" +apply from: "../../node_modules/react-native/react.gradle" /** * Set this to true to create two separate APKs instead of one: @@ -75,11 +81,9 @@ def enableSeparateBuildPerCPUArchitecture = false * Run Proguard to shrink the Java bytecode in release builds. */ def enableProguardInReleaseBuilds = false - android { compileSdkVersion 23 buildToolsVersion "23.0.1" - defaultConfig { applicationId "com.photobrowserexample" minSdkVersion 16 @@ -99,9 +103,29 @@ android { } } buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + debuggable true + signingConfig signingConfigs.debug + minifyEnabled true + } + } + signingConfigs { + debug { + // storeFile file("C:\\Users\\Administrator\\.android\\debug.keystore") + storeFile file("/Users/forp/Desktop/__test/debug.keystore") + keyAlias 'androiddebugkey' + keyPassword 'android' + storePassword 'android' + } release { - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + // storeFile file("E:\\VSCodeWorkSpace\\YuanXinMobileOffice\\key.keystore") + storeFile file("/Users/forp/Desktop/__test/debug.keystore") + keyAlias 'androiddebugkey' + keyPassword 'android' + storePassword 'android' } } // applicationVariants are e.g. debug, release @@ -109,7 +133,7 @@ android { variant.outputs.each { output -> // For each separate APK per architecture, set a unique version code as described here: // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits - def versionCodes = ["armeabi-v7a":1, "x86":2] + def versionCodes = ["armeabi-v7a": 1, "x86": 2] def abi = output.getFilter(OutputFile.ABI) if (abi != null) { // null for the universal-debug, universal-release variants output.versionCodeOverride = @@ -117,10 +141,27 @@ android { } } } + productFlavors { + } + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } } dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:+" // From node_modules + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.facebook.react:react-native:+' + // From node_modules +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' } + diff --git a/Example/android/app/proguard-rules.pro b/Example/android/app/proguard-rules.pro index 7d72e46..48361a9 100644 --- a/Example/android/app/proguard-rules.pro +++ b/Example/android/app/proguard-rules.pro @@ -26,11 +26,14 @@ # See http://sourceforge.net/p/proguard/bugs/466/ -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters +-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip # Do not strip any method/class that is annotated with @DoNotStrip -keep @com.facebook.proguard.annotations.DoNotStrip class * +-keep @com.facebook.common.internal.DoNotStrip class * -keepclassmembers class * { @com.facebook.proguard.annotations.DoNotStrip *; + @com.facebook.common.internal.DoNotStrip *; } -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { @@ -51,9 +54,9 @@ -keepattributes Signature -keepattributes *Annotation* --keep class com.squareup.okhttp.** { *; } --keep interface com.squareup.okhttp.** { *; } --dontwarn com.squareup.okhttp.** +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-dontwarn okhttp3.** # okio @@ -61,7 +64,3 @@ -dontwarn java.nio.file.* -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn okio.** - -# stetho - --dontwarn com.facebook.stetho.** diff --git a/Example/android/app/src/main/AndroidManifest.xml b/Example/android/app/src/main/AndroidManifest.xml index b891963..9a79830 100644 --- a/Example/android/app/src/main/AndroidManifest.xml +++ b/Example/android/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ getPackages() { - return Arrays.asList( - new MainReactPackage() - ); + protected void onResume() { + super.onResume(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onHostResume(this, this); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onHostDestroy(this); + } + } + + // 如果JavaScript端不处理相应的事件,你的invokeDefaultOnBackPressed方法会被调用。默认情况,这会直接结束你的Activity。 + @Override + public void invokeDefaultOnBackPressed() { + super.onBackPressed(); + } + + @Override + public void onBackPressed() { + if (mReactInstanceManager != null) { + mReactInstanceManager.onBackPressed(); + } else { + super.onBackPressed(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onActivityResult(this, requestCode, resultCode, data); + } } } diff --git a/Example/android/app/src/main/java/com/photobrowserexample/MainApplication.java b/Example/android/app/src/main/java/com/photobrowserexample/MainApplication.java new file mode 100644 index 0000000..c113852 --- /dev/null +++ b/Example/android/app/src/main/java/com/photobrowserexample/MainApplication.java @@ -0,0 +1,52 @@ +package com.photobrowserexample; + +import android.app.Application; +import android.app.Service; +import android.os.Vibrator; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.shell.MainReactPackage; + +import java.util.Arrays; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + public Vibrator mVibrator; + + @Override + public void onCreate() { + super.onCreate(); + } + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + + + /** + * Returns whether dev mode should be enabled. + * This enables e.g. the dev menu. + */ + @Override + protected boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + /** + * A list of packages used by the app. If the app uses additional views + * or modules besides the default ones, add more packages here. + */ + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage() + ); + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } +} diff --git a/Example/android/backup/build.gradle b/Example/android/backup/build.gradle new file mode 100644 index 0000000..7fc5acd --- /dev/null +++ b/Example/android/backup/build.gradle @@ -0,0 +1,142 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for example, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"] + * ] + */ + +apply from: "react.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + applicationId "com.photobrowserexample" + minSdkVersion 16 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + ndk { + abiFilters "armeabi-v7a", "x86" + } + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86" + } + } + buildTypes { + release { + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + signingConfigs { + debug { + // storeFile file("C:\\Users\\Administrator\\.android\\debug.keystore") + storeFile file("/Users/forp/Desktop/__test/debug.keystore") + keyAlias 'androiddebugkey' + keyPassword 'android' + storePassword 'android' + } + release { + // storeFile file("E:\\VSCodeWorkSpace\\YuanXinMobileOffice\\key.keystore") + storeFile file("/Users/forp/Desktop/__test/debug.keystore") + keyAlias 'androiddebugkey' + keyPassword 'android' + storePassword 'android' + } + } + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits + def versionCodes = ["armeabi-v7a":1, "x86":2] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } + } + } +} + +dependencies { + compile fileTree(dir: "libs", include: ["*.jar"]) + compile "com.android.support:appcompat-v7:23.0.1" + compile "com.facebook.react:react-native:+" // From node_modules +} diff --git a/Example/android/backup/proguard-rules.pro b/Example/android/backup/proguard-rules.pro new file mode 100644 index 0000000..7d72e46 --- /dev/null +++ b/Example/android/backup/proguard-rules.pro @@ -0,0 +1,67 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Disabling obfuscation is useful if you collect stack traces from production crashes +# (unless you are using a system that supports de-obfuscate the stack traces). +-dontobfuscate + +# React Native + +# Keep our interfaces so they can be used by other ProGuard rules. +# See http://sourceforge.net/p/proguard/bugs/466/ +-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip +-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters + +# Do not strip any method/class that is annotated with @DoNotStrip +-keep @com.facebook.proguard.annotations.DoNotStrip class * +-keepclassmembers class * { + @com.facebook.proguard.annotations.DoNotStrip *; +} + +-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { + void set*(***); + *** get*(); +} + +-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } +-keep class * extends com.facebook.react.bridge.NativeModule { *; } +-keepclassmembers,includedescriptorclasses class * { native ; } +-keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } + +-dontwarn com.facebook.react.** + +# okhttp + +-keepattributes Signature +-keepattributes *Annotation* +-keep class com.squareup.okhttp.** { *; } +-keep interface com.squareup.okhttp.** { *; } +-dontwarn com.squareup.okhttp.** + +# okio + +-keep class sun.misc.Unsafe { *; } +-dontwarn java.nio.file.* +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn okio.** + +# stetho + +-dontwarn com.facebook.stetho.** diff --git a/Example/android/build.gradle b/Example/android/build.gradle index 403a007..ef90680 100644 --- a/Example/android/build.gradle +++ b/Example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:2.2.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/Example/android/gradle/wrapper/gradle-wrapper.properties b/Example/android/gradle/wrapper/gradle-wrapper.properties index b9fbfab..f89ce5d 100644 --- a/Example/android/gradle/wrapper/gradle-wrapper.properties +++ b/Example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Sat Dec 10 15:43:49 CST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/Example/ios/PhotoBrowserExample/AppDelegate.m b/Example/ios/PhotoBrowserExample/AppDelegate.m index a3fea98..32840e9 100644 --- a/Example/ios/PhotoBrowserExample/AppDelegate.m +++ b/Example/ios/PhotoBrowserExample/AppDelegate.m @@ -9,6 +9,8 @@ #import "AppDelegate.h" +#import "RCTBundleURLProvider.h" + #import "RCTRootView.h" @implementation AppDelegate @@ -42,6 +44,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( */ // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + +#ifdef DEBUG + jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; +#else + jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; +#endif RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"PhotoBrowserExample" diff --git a/Example/package.json b/Example/package.json index c9b17f8..f6832c8 100644 --- a/Example/package.json +++ b/Example/package.json @@ -6,8 +6,8 @@ "start": "node node_modules/react-native/local-cli/cli.js start" }, "dependencies": { - "react": "^15.2.1", - "react-native": "^0.32.0", + "react": "^15.4.0", + "react-native": "^0.39.0", "react-native-photo-browser": "https://github.com/ksti/react-native-photo-browser.git" } } From 5e45ee83dbff09c4b973cda908220a64e12066e2 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Thu, 15 Dec 2016 19:25:16 +0800 Subject: [PATCH 31/35] add feature of notSupportedError --- lib/.DS_Store | Bin 6148 -> 0 bytes lib/FullScreenContainer.js | 4 ++ lib/GridContainer.js | 3 ++ lib/index.js | 8 ++++ lib/media/Photo.js | 93 +++++++++++++++++++++++++++++++++++-- 5 files changed, 104 insertions(+), 4 deletions(-) delete mode 100644 lib/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index 29c73d491f803168f70ecc82b6ef368c7f1280ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~%Wl&^6ozM-6zsT>j3`p2g5)hC3x^Q8bwj&BAR@U+g(wOh*&-tuJF=ZbRTRmq zF4&^J0C$N8-~kE+9s$-|o`D@_E`*rSCA30wq?!NB%sDgh=h)*x2;tViuOnn4gfu8j z%N3~pU~HU~Ia`oDWl+rKNc$v=2{cwoe=b^eC<2PWNh83X-4Y_mLkStpKEEMNGu!@z z7fR*DQ>Qh(Vk}jSs<~uTt9RXAJaRKH8>B5S>6+(V>IcM2wyB@>wt{Fg42D5;E4kri zL2`!$Z^dy40mAo4hX$jrxqK~-GLJ?}=D>k4LR|5c%oO?8II3TssMdklOa5 zphHtiXh^eNKB)}ke%s4>u$X4<>zdv*SH|PIU9VYTQbg(nhO=_2+P9 znBU^z2s=Vmtq3RrMFJ(!G}->YdGz_en50^YfFkf;5y0gQccTTDB=^?2i(`AO1?3(T qW-Klj%2S|{+c9_8R=fg*8;n`Z0d=J2LZJsteF$(2s!|00DS;m~S;d?H diff --git a/lib/FullScreenContainer.js b/lib/FullScreenContainer.js index 94598d0..6e39be8 100644 --- a/lib/FullScreenContainer.js +++ b/lib/FullScreenContainer.js @@ -56,6 +56,7 @@ export default class FullScreenContainer extends React.Component { useCircleProgress: PropTypes.bool, onActionButton: PropTypes.func, forceLoadPhoto: PropTypes.bool, + notSupportedError: PropTypes.string, }; static defaultProps = { @@ -64,6 +65,7 @@ export default class FullScreenContainer extends React.Component { displaySelectionButtons: false, enableGrid: true, onGridButtonTap: () => {}, + notSupportedError: 'sorry, not supported!' }; constructor(props, context) { @@ -270,6 +272,8 @@ export default class FullScreenContainer extends React.Component { height={screen.height} lazyLoad useCircleProgress={useCircleProgress} + mimeTypeOrExt={media.mimeTypeOrExt} + notSupportedError={this.props.notSupportedError} uri={media.photo} transformable={true} displaySelectionButtons={displaySelectionButtons} diff --git a/lib/GridContainer.js b/lib/GridContainer.js index f534079..cec2690 100644 --- a/lib/GridContainer.js +++ b/lib/GridContainer.js @@ -21,6 +21,7 @@ export default class GridContainer extends React.Component { displaySelectionButtons: PropTypes.bool, onPhotoTap: PropTypes.func, itemPerRow: PropTypes.number, + notSupportedError: PropTypes.string, /* * refresh the list to apply selection change @@ -62,6 +63,8 @@ export default class GridContainer extends React.Component { thumbnail progressImage={require('../Assets/hourglass.png')} displaySelectionButtons={displaySelectionButtons} + mimeTypeOrExt={media.mimeTypeOrExt} + notSupportedError={this.props.notSupportedError} uri={media.thumb || media.photo} selected={media.selected} onSelection={(isSelected) => { diff --git a/lib/index.js b/lib/index.js index db613ba..6a2f358 100644 --- a/lib/index.js +++ b/lib/index.js @@ -87,6 +87,11 @@ export default class PhotoBrowser extends React.Component { * Whether to force load photo */ forceLoadPhoto: PropTypes.bool, + + /* + * not supported error + */ + notSupportedError: PropTypes.string, }; static defaultProps = { @@ -227,6 +232,7 @@ export default class PhotoBrowser extends React.Component { useGallery, initialIndex, forceLoadPhoto, + notSupportedError, } = this.props; const { dataSource, @@ -259,6 +265,7 @@ export default class PhotoBrowser extends React.Component { onPhotoTap={this._onGridPhotoTap} onMediaSelection={this._onMediaSelection} itemPerRow={itemPerRow} + notSupportedError={notSupportedError} /> ); @@ -285,6 +292,7 @@ export default class PhotoBrowser extends React.Component { triggerTopBarStatus={this._triggerTopBarStatus} useGallery={useGallery} forceLoadPhoto={forceLoadPhoto} + notSupportedError={notSupportedError} /> ); } diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 13c5a8e..30dd9d3 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -5,6 +5,7 @@ import { Image, StyleSheet, View, + Text, TouchableWithoutFeedback, ProgressBarAndroid, Platform, @@ -81,6 +82,16 @@ export default class Photo extends Component { * iOS only */ useCircleProgress: PropTypes.bool, + + /* + * supported mimetype + */ + mimeTypeOrExt: PropTypes.string, + + /* + * not supported error + */ + notSupportedError: PropTypes.string, }; static defaultProps = { @@ -89,6 +100,8 @@ export default class Photo extends Component { lazyLoad: false, selected: false, transformable: false, + mimeTypeOrExt: 'jpg', + notSupportedError: 'sorry, not supported!' }; constructor(props) { @@ -99,6 +112,24 @@ export default class Photo extends Component { this._onLoad = this._onLoad.bind(this); this._toggleSelection = this._toggleSelection.bind(this); + this.supportedMimeType = [ + { + mimeType: 'image/jpeg', + ext: [ + 'jpe', + 'jpeg', + 'jpg', + ], + }, + { + mimeType: 'image/png', + ext: [ + 'png', + 'x-png', + ], + }, + ] + const { lazyLoad, uri } = props; this.state = { @@ -134,6 +165,33 @@ export default class Photo extends Component { return this.transformableImage; } + getSupportedMimeType() { + return this.supportedMimeType; + } + + isSupported(mimeTypeOrExt) { + if (typeof mimeTypeOrExt !== 'string') return false; + let supported = false; + this.supportedMimeType.map((mimeTypeObject, index) => { + if (supported) { + return true; + }; + if (mimeTypeOrExt === mimeTypeObject.mimeType) { + supported = true; + return supported; + } else { + let supportedExt = mimeTypeObject.ext; + supportedExt.map((ext, extIndex) => { + if (mimeTypeOrExt === ext) { + supported = true; + return supported; + }; + }); + } + }); + return supported; + } + _onProgress(event) { const progress = event.nativeEvent.loaded / event.nativeEvent.total; if (!this.props.thumbnail && progress !== this.state.progress) { @@ -191,11 +249,33 @@ export default class Photo extends Component { return null; } + _renderNotSupportedType() { + let notSupportedErrorText = this.props.notSupportedError || 'sorry, not supported!'; + return ( + + + + {notSupportedErrorText} + + + ); + } + _renderErrorIcon() { return ( - + + + ); } @@ -262,9 +342,14 @@ export default class Photo extends Component { height: height || screen.height, }; + let errorOrProgressView = error ? this._renderErrorIcon() : this._renderProgressIndicator(); + if (!this.isSupported(this.props.mimeTypeOrExt)) { + errorOrProgressView = this._renderNotSupportedType(); + }; + return ( - {error ? this._renderErrorIcon() : this._renderProgressIndicator()} + {errorOrProgressView} { transformable ? ( Date: Sun, 18 Dec 2016 17:33:57 +0800 Subject: [PATCH 32/35] isSupported justify by lowercase --- lib/media/Photo.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 30dd9d3..107b807 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -169,20 +169,21 @@ export default class Photo extends Component { return this.supportedMimeType; } - isSupported(mimeTypeOrExt) { + isSupported = (mimeTypeOrExt) => { if (typeof mimeTypeOrExt !== 'string') return false; + let lowercaseMimeTypeOrExt = mimeTypeOrExt.toLowerCase(); let supported = false; this.supportedMimeType.map((mimeTypeObject, index) => { if (supported) { return true; }; - if (mimeTypeOrExt === mimeTypeObject.mimeType) { + if (lowercaseMimeTypeOrExt === mimeTypeObject.mimeType) { supported = true; return supported; } else { let supportedExt = mimeTypeObject.ext; supportedExt.map((ext, extIndex) => { - if (mimeTypeOrExt === ext) { + if (lowercaseMimeTypeOrExt === ext) { supported = true; return supported; }; From 0539de7e5ce5567ba32c32b4a09e85b5bd49b101 Mon Sep 17 00:00:00 2001 From: GJS <1353990812@qq.com> Date: Sun, 18 Dec 2016 18:29:39 +0800 Subject: [PATCH 33/35] DS_Store --- lib/.DS_Store | Bin 0 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..de0a5cd2a55328fd3bfbe083cfe2af2d77e82c3e GIT binary patch literal 6148 zcmeHKI|>3Z5S{S@f{mqRuHX%V=n1@lf+B(+5VYRPb9pr1e41sk(?WRzlb1~9CFB)5 zJ0ha<+jb^05s?wxP#!jP&GyYZ*2{+o4eb zDnJFO02QDDpH?6%>}dSygLxhmpaMUyfPEhd+^{A#f&S^h;4J`ffUq0p-b( Date: Tue, 14 Feb 2017 11:01:50 +0800 Subject: [PATCH 34/35] default is supported when mimeTypeOrExt is missed --- lib/media/Photo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/media/Photo.js b/lib/media/Photo.js index 107b807..d85ce1a 100644 --- a/lib/media/Photo.js +++ b/lib/media/Photo.js @@ -170,6 +170,7 @@ export default class Photo extends Component { } isSupported = (mimeTypeOrExt) => { + if (!mimeTypeOrExt) return true; // default is support if (typeof mimeTypeOrExt !== 'string') return false; let lowercaseMimeTypeOrExt = mimeTypeOrExt.toLowerCase(); let supported = false; From c6495c6afb2f83e20a69943ee47e07a63db0c8d0 Mon Sep 17 00:00:00 2001 From: gjs <1353990812@qq.com> Date: Wed, 3 Jan 2018 16:54:58 +0800 Subject: [PATCH 35/35] avoid undefined crash --- lib/.DS_Store | Bin 6148 -> 0 bytes lib/Gallery.js | 15 +++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 lib/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index de0a5cd2a55328fd3bfbe083cfe2af2d77e82c3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKI|>3Z5S{S@f{mqRuHX%V=n1@lf+B(+5VYRPb9pr1e41sk(?WRzlb1~9CFB)5 zJ0ha<+jb^05s?wxP#!jP&GyYZ*2{+o4eb zDnJFO02QDDpH?6%>}dSygLxhmpaMUyfPEhd+^{A#f&S^h;4J`ffUq0p-b( { - this.getViewPagerInstance().onResponderGrant(evt, gestureState); + this.getViewPagerInstance() && this.getViewPagerInstance().onResponderGrant(evt, gestureState); }, onMove: (evt, gestureState) => { - this.getViewPagerInstance().onResponderMove(evt, gestureState); + this.getViewPagerInstance() && this.getViewPagerInstance().onResponderMove(evt, gestureState); }, onEnd: (evt, gestureState, disableSettle) => { - this.getViewPagerInstance().onResponderRelease(evt, gestureState, disableSettle); + this.getViewPagerInstance() && this.getViewPagerInstance().onResponderRelease(evt, gestureState, disableSettle); } } this.imageResponder = { onStart: ((evt, gestureState) => { - this.getCurrentImageTransformer().onResponderGrant(evt, gestureState); + this.getCurrentImageTransformer() && this.getCurrentImageTransformer().onResponderGrant(evt, gestureState); }), onMove: (evt, gestureState) => { - this.getCurrentImageTransformer().onResponderMove(evt, gestureState); + this.getCurrentImageTransformer() && this.getCurrentImageTransformer().onResponderMove(evt, gestureState); }, onEnd: (evt, gestureState) => { - this.getCurrentImageTransformer().onResponderRelease(evt, gestureState); + this.getCurrentImageTransformer() && this.getCurrentImageTransformer().onResponderRelease(evt, gestureState); } } } @@ -125,6 +125,9 @@ export default class Gallery extends Component { return false; } const viewTransformer = this.getCurrentImageTransformer(); + if (!viewTransformer) { + return false; + } const space = viewTransformer.getAvailableTranslateSpace(); const dx = gestureState.moveX - gestureState.previousMoveX;