From 41f511e2339b4292566d4cdf33fa2164e555005c Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 16 Aug 2019 18:26:13 +0100 Subject: [PATCH] list selection mode and deleting published items (#26) --- src/component/fileListItem/view.js | 18 +++- src/component/uriBar/view.js | 140 +++++++++++++++++++---------- src/page/publishes/index.js | 2 + src/page/publishes/view.js | 86 +++++++++++++++++- src/styles/discover.js | 8 -- src/styles/fileList.js | 10 +++ src/styles/uriBar.js | 34 +++++++ 7 files changed, 237 insertions(+), 61 deletions(-) diff --git a/src/component/fileListItem/view.js b/src/component/fileListItem/view.js index 9dbf779..11237b5 100644 --- a/src/component/fileListItem/view.js +++ b/src/component/fileListItem/view.js @@ -46,6 +46,15 @@ class FileListItem extends React.PureComponent { navigateToUri(navigation, shortUrl || uri, { autoplay }); }; + onPressHandler = () => { + const { claim, onPress } = this.props; + if (onPress) { + onPress(claim); + } else { + this.defaultOnPress(); + } + }; + render() { const { blackListedOutpoints, @@ -63,6 +72,8 @@ class FileListItem extends React.PureComponent { navigation, thumbnail, hideChannel, + onLongPress, + selected, title, } = this.props; @@ -95,7 +106,7 @@ class FileListItem extends React.PureComponent { return ( - + onLongPress(claim)}> + {selected && ( + + + + )} {fileInfo && fileInfo.completed && fileInfo.download_path && ( )} diff --git a/src/component/uriBar/view.js b/src/component/uriBar/view.js index bed341b..d2350e3 100644 --- a/src/component/uriBar/view.js +++ b/src/component/uriBar/view.js @@ -1,12 +1,12 @@ // @flow import React from 'react'; import { SEARCH_TYPES, isNameValid, isURIValid, normalizeURI } from 'lbry-redux'; -import { FlatList, Keyboard, TextInput, View } from 'react-native'; +import { FlatList, Keyboard, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { navigateToUri } from 'utils/helper'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import UriBarItem from './internal/uri-bar-item'; +import Icon from 'react-native-vector-icons/FontAwesome5'; import NavigationButton from 'component/navigationButton'; -import discoverStyle from 'styles/discover'; import uriBarStyle from 'styles/uriBar'; class UriBar extends React.PureComponent { @@ -16,6 +16,16 @@ class UriBar extends React.PureComponent { keyboardDidHideListener = null; + state = { + changeTextTimeout: null, + currentValue: null, + inputText: null, + focused: false, + + // TODO: Add a setting to enable / disable direct search? + directSearch: true, + }; + componentDidMount() { this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide); this.setSelection(); @@ -36,18 +46,6 @@ class UriBar extends React.PureComponent { } } - constructor(props) { - super(props); - this.state = { - changeTextTimeout: null, - currentValue: null, - inputText: null, - focused: false, - // TODO: Add a setting to enable / disable direct search? - directSearch: true, - }; - } - handleChangeText = text => { const newValue = text || ''; clearTimeout(this.state.changeTextTimeout); @@ -136,7 +134,17 @@ class UriBar extends React.PureComponent { } render() { - const { navigation, suggestions, query, value, belowOverlay } = this.props; + const { + belowOverlay, + navigation, + onExitSelectionMode, + onDeleteActionPressed, + query, + selectedItemCount, + selectionMode, + suggestions, + value, + } = this.props; if (this.state.currentValue === null) { this.setState({ currentValue: value }); } @@ -146,42 +154,78 @@ class UriBar extends React.PureComponent { // TODO: Add optional setting to enable URI / search bar suggestions /* if (this.state.focused) { style.push(uriBarStyle.inFocus); } */ + // TODO: selectionModeActions should be dynamically created / specified return ( - navigation.openDrawer()} - /> - { - this.textInput = ref; - }} - autoCorrect={false} - style={uriBarStyle.uriText} - onLayout={() => { - this.setSelection(); - }} - selectTextOnFocus - placeholder={'Search movies, music, and more'} - underlineColorAndroid={'transparent'} - numberOfLines={1} - clearButtonMode={'while-editing'} - value={this.state.currentValue} - returnKeyType={'go'} - inlineImageLeft={'baseline_search_black_24'} - inlineImagePadding={16} - onFocus={() => this.setState({ focused: true })} - onBlur={() => { - this.setState({ focused: false }); - this.setSelection(); - }} - onChangeText={this.handleChangeText} - onSubmitEditing={this.handleSubmitEditing} - /> + {selectionMode && ( + + + { + if (onExitSelectionMode) { + onExitSelectionMode(); + } + }} + > + + + {selectedItemCount > 0 && {selectedItemCount}} + + + + { + if (onDeleteActionPressed) { + onDeleteActionPressed(); + } + }} + > + + + + + )} + + {!selectionMode && ( + navigation.openDrawer()} + /> + )} + {!selectionMode && ( + { + this.textInput = ref; + }} + autoCorrect={false} + style={uriBarStyle.uriText} + onLayout={() => { + this.setSelection(); + }} + selectTextOnFocus + placeholder={'Search movies, music, and more'} + underlineColorAndroid={'transparent'} + numberOfLines={1} + clearButtonMode={'while-editing'} + value={this.state.currentValue} + returnKeyType={'go'} + inlineImageLeft={'baseline_search_black_24'} + inlineImagePadding={16} + onFocus={() => this.setState({ focused: true })} + onBlur={() => { + this.setState({ focused: false }); + this.setSelection(); + }} + onChangeText={this.handleChangeText} + onSubmitEditing={this.handleSubmitEditing} + /> + )} {this.state.focused && !this.state.directSearch && ( ({ }); const perform = dispatch => ({ + abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)), fetchMyClaims: () => dispatch(doFetchClaimListMine()), checkPendingPublishes: () => dispatch(doCheckPendingPublishes()), pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_PUBLISHES)), diff --git a/src/page/publishes/view.js b/src/page/publishes/view.js index 3518c66..aeb6a41 100644 --- a/src/page/publishes/view.js +++ b/src/page/publishes/view.js @@ -1,5 +1,5 @@ import React from 'react'; -import { ActivityIndicator, FlatList, Text, TouchableOpacity, View } from 'react-native'; +import { ActivityIndicator, Alert, FlatList, Text, TouchableOpacity, View } from 'react-native'; import Button from 'component/button'; import Colors from 'styles/colors'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api @@ -7,9 +7,15 @@ import FileListItem from 'component/fileListItem'; import FloatingWalletBalance from 'component/floatingWalletBalance'; import UriBar from 'component/uriBar'; import publishStyle from 'styles/publish'; -import { __ } from 'utils/helper'; +import { __, navigateToUri } from 'utils/helper'; class PublishesPage extends React.PureComponent { + state = { + selectionMode: false, + selectedUris: [], + selectedClaimsMap: {}, + }; + didFocusListener; componentWillMount() { @@ -36,12 +42,67 @@ class PublishesPage extends React.PureComponent { checkPendingPublishes(); }; + addOrRemoveItem = (uri, claim) => { + const { selectedClaimsMap } = this.state; + let selectedUris = [...this.state.selectedUris]; + + if (selectedUris.includes(uri)) { + delete selectedClaimsMap[uri]; + selectedUris.splice(selectedUris.indexOf(uri), 1); + } else { + selectedClaimsMap[uri] = claim; + selectedUris.push(uri); + } + + this.setState({ selectionMode: selectedUris.length > 0, selectedUris, selectedClaimsMap }); + }; + + handleSelectItem = (uri, claim) => { + this.addOrRemoveItem(uri, claim); + }; + + handleItemLongPress = (uri, claim) => { + this.addOrRemoveItem(uri, claim); + }; + + onExitSelectionMode = () => { + this.setState({ selectionMode: false, selectedUris: [], selectedClaimsMap: {} }); + }; + + onDeleteActionPressed = () => { + const { abandonClaim } = this.props; + const { selectedClaimsMap } = this.state; + + // show confirm alert + Alert.alert(__('Unpublish'), __('Are you sure you want to unpublish the selected content?'), [ + { text: __('No') }, + { + text: __('Yes'), + onPress: () => { + const uris = Object.keys(selectedClaimsMap); + uris.forEach(uri => { + const { txid, nout } = selectedClaimsMap[uri]; + abandonClaim(txid, nout); + }); + this.onExitSelectionMode(); + }, + }, + ]); + }; + render() { const { fetching, navigation, uris } = this.props; + const { selectionMode, selectedUris } = this.state; return ( - + {fetching && ( @@ -65,11 +126,28 @@ class PublishesPage extends React.PureComponent { ( - + { + if (selectionMode) { + this.handleSelectItem(item, claim); + } else { + // TODO: when shortUrl is available for my claims, navigate to that URL instead + navigateToUri(navigation, item); + } + }} + onLongPress={claim => this.handleItemLongPress(item, claim)} + navigation={navigation} + /> )} data={uris} keyExtractor={(item, index) => item} diff --git a/src/styles/discover.js b/src/styles/discover.js index 803a0cf..e9e747e 100644 --- a/src/styles/discover.js +++ b/src/styles/discover.js @@ -167,14 +167,6 @@ const discoverStyle = StyleSheet.create({ textAlign: 'center', color: '#0c604b', }, - drawerMenuButton: { - height: '100%', - justifyContent: 'center', - }, - drawerHamburger: { - marginLeft: 16, - marginRight: 16, - }, rightHeaderIcon: { marginRight: 16, }, diff --git a/src/styles/fileList.js b/src/styles/fileList.js index 4006569..1b0a5a2 100644 --- a/src/styles/fileList.js +++ b/src/styles/fileList.js @@ -38,6 +38,16 @@ const fileListStyle = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, + selectedOverlay: { + position: 'absolute', + left: 0, + top: 0, + width: thumbnailWidth, + height: thumbnailHeight, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: '#000000aa', + }, title: { fontFamily: 'Inter-UI-SemiBold', fontSize: screenWidthPixels <= 720 ? 12 : 14, diff --git a/src/styles/uriBar.js b/src/styles/uriBar.js index ea5722e..668937d 100644 --- a/src/styles/uriBar.js +++ b/src/styles/uriBar.js @@ -20,6 +20,10 @@ const uriBarStyle = StyleSheet.create({ containerElevated: { elevation: 4, }, + drawerHamburger: { + marginLeft: 16, + marginRight: 16, + }, uriText: { backgroundColor: Colors.VeryLightGrey, borderRadius: 24, @@ -73,6 +77,36 @@ const uriBarStyle = StyleSheet.create({ justifyContent: 'center', flex: 3, }, + selectionModeBar: { + flex: 1, + height: 46, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + }, + selectionModeLeftBar: { + flexDirection: 'row', + alignItems: 'center', + marginLeft: 16, + }, + selectionModeActions: { + flexDirection: 'row', + alignItems: 'center', + marginRight: 16, + }, + backTouchArea: { + height: '100%', + alignItems: 'center', + }, + actionTouchArea: { + height: '100%', + alignItems: 'center', + }, + itemCount: { + fontFamily: 'Inter-UI-Regular', + fontSize: 20, + marginLeft: 30, + }, }); export default uriBarStyle;