Compare commits

...

11 commits

Author SHA1 Message Date
Akinwale Ariwodola
78f2b4f3be use err.message conditionally, and isChannel from parseURI. 2019-09-13 08:14:24 +01:00
Akinwale Ariwodola
0fe32e1a36 cleanup 2019-09-11 12:36:41 +01:00
Akinwale Ariwodola
f008d95aa6 maintain form state when user navigates away 2019-09-11 12:32:54 +01:00
Akinwale Ariwodola
c4218d9f8b channel creator updates after review 2019-09-11 08:22:56 +01:00
Akinwale Ariwodola
e95786b904 do not list channels in pending abandon state 2019-09-09 15:33:48 +01:00
Akinwale Ariwodola
f02fdd9979 channel creator updates 2019-09-09 11:14:53 +01:00
Akinwale Ariwodola
563a9135ce fix merge conflicts 2019-09-09 09:31:23 +01:00
Akinwale Ariwodola
39eb2b1a96 fix tags for edit 2019-09-02 13:31:36 +01:00
Akinwale Ariwodola
2f0014be08 channel creator updates. upload image assets. 2019-09-02 13:03:58 +01:00
Akinwale Ariwodola
27c0ac7585 support optional parameters 2019-08-30 20:03:31 +01:00
Akinwale Ariwodola
44856e1ba1 channel creator page 2019-08-30 18:31:12 +01:00
27 changed files with 1703 additions and 35 deletions

14
package-lock.json generated
View file

@ -5574,8 +5574,8 @@
}
},
"lbry-redux": {
"version": "github:lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
"from": "github:lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
"version": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
"from": "github:lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
"requires": {
"proxy-polyfill": "0.1.6",
"reselect": "^3.0.0",
@ -8039,11 +8039,6 @@
}
}
},
"react-native-document-picker": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-3.2.4.tgz",
"integrity": "sha512-5l0/fkgasUZdIk9jUUkReDtNCQn2yg1+BrMPHMt45c/NVmE15ThnhIuDj8/n8h1F1RlhUb3SzF86ANK4OdZAiQ=="
},
"react-native-exception-handler": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.9.0.tgz",
@ -9124,6 +9119,11 @@
"object-assign": "^4.1.1"
}
},
"seedrandom": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.3.tgz",
"integrity": "sha512-PJLhhxIMjlMJaiIRtqiVW061EZn3cS+waZkbFe7eCa2R3g88HbNdWmw4NTFG1w5unxd0GeNaUUxZJP7gPAzSDQ=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",

View file

@ -12,7 +12,7 @@
"base-64": "^0.1.0",
"@expo/vector-icons": "^8.1.0",
"gfycat-style-urls": "^1.0.3",
"lbry-redux": "lbryio/lbry-redux#362d764c4c0de23032b6871b4d54207dc548028c",
"lbry-redux": "lbryio/lbry-redux#3133ea60b0302c162f7b6f67cc858997f1d2ab52",
"lbryinc": "lbryio/lbryinc#b9f354ae50bd57691765a7d042c5054167878bf4",
"lodash": ">=4.17.11",
"merge": ">=1.2.1",
@ -22,7 +22,6 @@
"@react-native-community/async-storage": "^1.5.1",
"react-native-camera": "^2.11.1",
"react-native-country-picker-modal": "^0.6.2",
"react-native-document-picker": "^3.2.4",
"react-native-exception-handler": "2.9.0",
"react-native-fast-image": "^6.1.1",
"react-native-fs": "^2.13.3",
@ -44,7 +43,8 @@
"redux-persist-transform-compress": "^4.2.0",
"redux-persist-transform-filter": "0.0.18",
"redux-thunk": "^2.3.0",
"rn-fetch-blob": "0.10.15"
"rn-fetch-blob": "0.10.15",
"seedrandom": "3.0.3"
},
"devDependencies": {
"@babel/core": "^7.5.4",

View file

@ -1,5 +1,6 @@
import React from 'react';
import AboutPage from 'page/about';
import ChannelCreatorPage from 'page/channelCreator';
import DiscoverPage from 'page/discover';
import DownloadsPage from 'page/downloads';
import DrawerContent from 'component/drawerContent';
@ -159,6 +160,12 @@ const drawer = createDrawerNavigator(
drawerIcon: ({ tintColor }) => <Icon name="wallet" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
ChannelCreator: {
screen: ChannelCreatorPage,
navigationOptions: {
drawerIcon: ({ tintColor }) => <Icon name="at" size={drawerIconSize} style={{ color: tintColor }} />,
},
},
Publish: {
screen: PublishPage,
navigationOptions: {

View file

@ -13,10 +13,15 @@ export default class ChannelIconItem extends React.PureComponent {
autothumbStyle.autothumbBlue,
autothumbStyle.autothumbLightBlue,
autothumbStyle.autothumbCyan,
autothumbStyle.autothumbTeal,
autothumbStyle.autothumbGreen,
autothumbStyle.autothumbYellow,
autothumbStyle.autothumbOrange,
autothumbStyle.autothumbDeepPurple,
autothumbStyle.autothumbAmber,
autothumbStyle.autothumbLime,
autothumbStyle.autothumbLightGreen,
autothumbStyle.autothumbDeepOrange,
autothumbStyle.autothumbBrown,
];
state = {

View file

@ -204,7 +204,11 @@ class ClaimList extends React.PureComponent {
const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options);
const uris = claimSearchByQuery[claimSearchKey];
let uris = claimSearchByQuery[claimSearchKey];
if (uris) {
uris = uris.filter(uri => uri && uri.length > 0);
}
if (Constants.ORIENTATION_VERTICAL === orientation) {
return (

View file

@ -12,6 +12,7 @@ const groupedMenuItems = {
{ icon: 'globe-americas', label: 'All content', route: Constants.DRAWER_ROUTE_TRENDING },
],
'Your content': [
{ icon: 'at', label: 'Channels', route: Constants.DRAWER_ROUTE_CHANNEL_CREATOR },
{ icon: 'download', label: 'Library', route: Constants.DRAWER_ROUTE_MY_LBRY },
{ icon: 'cloud-upload-alt', label: 'Publishes', route: Constants.DRAWER_ROUTE_PUBLISHES },
{ icon: 'upload', label: 'New publish', route: Constants.DRAWER_ROUTE_PUBLISH },

View file

@ -67,11 +67,12 @@ export default class TagSearch extends React.PureComponent {
};
render() {
const { name, style, type, selectedTags = [], showNsfwTags } = this.props;
const { editable, name, style, type, selectedTags = [], showNsfwTags } = this.props;
return (
<View>
<TextInput
editable={editable}
style={tagStyle.searchInput}
placeholder={'Search for more tags'}
underlineColorAndroid={Colors.NextLbryGreen}

View file

@ -25,6 +25,9 @@ const Constants = {
PHASE_DETAILS: 'details',
PHASE_PUBLISH: 'publish',
PHASE_LIST: 'list',
PHASE_NEW: 'create',
CONTENT_TAB: 'content',
ABOUT_TAB: 'about',
@ -56,6 +59,11 @@ const Constants = {
ACTION_SORT_BY_ITEM_CHANGED: 'SORT_BY_ITEM_CHANGED',
ACTION_TIME_ITEM_CHANGED: 'TIME_ITEM_CHANGED',
ACTION_UPDATE_PUBLISH_FORM_STATE: 'UPDATE_PUBLISH_FORM_STATE',
ACTION_UPDATE_CHANNEL_FORM_STATE: 'UPDATE_CHANNEL_FORM_STATE',
ACTION_CLEAR_PUBLISH_FORM_STATE: 'CLEAR_PUBLISH_FORM_STATE',
ACTION_CLEAR_CHANNEL_FORM_STATE: 'CLEAR_CHANNEL_FORM_STATE',
ORIENTATION_HORIZONTAL: 'horizontal',
ORIENTATION_VERTICAL: 'vertical',
@ -69,6 +77,7 @@ const Constants = {
DRAWER_ROUTE_SUBSCRIPTIONS: 'Subscriptions',
DRAWER_ROUTE_MY_LBRY: 'Downloads',
DRAWER_ROUTE_PUBLISH: 'Publish',
DRAWER_ROUTE_PUBLISH_FORM: 'PublishForm',
DRAWER_ROUTE_PUBLISHES: 'Publishes',
DRAWER_ROUTE_REWARDS: 'Rewards',
DRAWER_ROUTE_WALLET: 'Wallet',
@ -77,6 +86,8 @@ const Constants = {
DRAWER_ROUTE_SEARCH: 'Search',
DRAWER_ROUTE_TRANSACTION_HISTORY: 'TransactionHistory',
DRAWER_ROUTE_TAG: 'Tag',
DRAWER_ROUTE_CHANNEL_CREATOR: 'ChannelCreator',
DRAWER_ROUTE_CHANNEL_CREATOR_FORM: 'ChannnelCreatorForm',
FULL_ROUTE_NAME_DISCOVER: 'DiscoverStack',
FULL_ROUTE_NAME_WALLET: 'WalletStack',
@ -146,4 +157,8 @@ export const DrawerRoutes = [
Constants.DRAWER_ROUTE_ABOUT,
Constants.DRAWER_ROUTE_SEARCH,
Constants.DRAWER_ROUTE_TRANSACTION_HISTORY,
Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
];
// sub-pages for main routes
export const InnerDrawerRoutes = [Constants.DRAWER_ROUTE_CHANNEL_CREATOR_FORM, Constants.DRAWER_ROUTE_PUBLISH_FORM];

View file

@ -37,6 +37,7 @@ import FilesystemStorage from 'redux-persist-filesystem-storage';
import createCompressor from 'redux-persist-transform-compress';
import createFilter from 'redux-persist-transform-filter';
import moment from 'moment';
import formReducer from 'redux/reducers/form';
import drawerReducer from 'redux/reducers/drawer';
import settingsReducer from 'redux/reducers/settings';
import thunk from 'redux-thunk';
@ -109,6 +110,7 @@ const reducers = persistCombineReducers(persistOptions, {
file: fileReducer,
fileInfo: fileInfoReducer,
filtered: filteredReducer,
form: formReducer,
homepage: homepageReducer,
nav: navigatorReducer,
notifications: notificationsReducer,

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { doFetchClaimsByChannel, makeSelectClaimForUri } from 'lbry-redux';
import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
import { doPopDrawerStack } from 'redux/actions/drawer';
import { doSetSortByItem, doSetTimeItem } from 'redux/actions/settings';
import { selectDrawerStack } from 'redux/selectors/drawer';
@ -7,6 +7,7 @@ import { selectSortByItem, selectTimeItem } from 'redux/selectors/settings';
import ChannelPage from './view';
const select = (state, props) => ({
channels: selectMyChannelClaims(state),
claim: makeSelectClaimForUri(props.uri)(state),
drawerStack: selectDrawerStack(state),
sortByItem: selectSortByItem(state),
@ -14,7 +15,6 @@ const select = (state, props) => ({
});
const perform = dispatch => ({
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
popDrawerStack: () => dispatch(doPopDrawerStack()),
setSortByItem: item => dispatch(doSetSortByItem(item)),
setTimeItem: item => dispatch(doSetTimeItem(item)),

View file

@ -2,6 +2,7 @@
import React from 'react';
import {
ActivityIndicator,
Alert,
Dimensions,
Image,
NativeModules,
@ -159,10 +160,46 @@ class ChannelPage extends React.PureComponent {
);
};
onEditPressed = () => {
const { claim, navigation } = this.props;
if (claim) {
const { permanent_url: permanentUrl } = claim;
navigation.navigate({
routeName: Constants.DRAWER_ROUTE_CHANNEL_CREATOR,
params: { editChannelUrl: permanentUrl },
});
}
};
onDeletePressed = () => {
const { abandonClaim, claim, navigation } = this.props;
if (claim) {
const { txid, nout } = claim;
// show confirm alert
Alert.alert(
__('Delete channel'),
__('Are you sure you want to delete this channel?'),
[
{ text: __('No') },
{
text: __('Yes'),
onPress: () => {
abandonClaim(txid, nout);
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_CHANNEL_CREATOR });
},
},
],
{ cancelable: true }
);
}
};
render() {
const { claim, navigation, uri, drawerStack, popDrawerStack, sortByItem, timeItem } = this.props;
const { channels, claim, navigation, uri, drawerStack, popDrawerStack, sortByItem, timeItem } = this.props;
const { name, permanent_url: permanentUrl } = claim;
const { autoStyle, showSortPicker, showTimePicker } = this.state;
const ownedChannel = channels ? channels.map(channel => channel.permanent_url).includes(permanentUrl) : false;
let thumbnailUrl,
coverUrl,
@ -218,12 +255,32 @@ class ChannelPage extends React.PureComponent {
</View>
<View style={channelPageStyle.subscribeButtonContainer}>
<SubscribeButton style={channelPageStyle.subscribeButton} uri={fullUri} name={name} />
<SubscribeNotificationButton
style={[channelPageStyle.subscribeButton, channelPageStyle.bellButton]}
uri={fullUri}
name={name}
/>
{ownedChannel && (
<Button
style={channelPageStyle.actionButton}
theme={'light'}
icon={'edit'}
text={'Edit'}
onPress={this.onEditPressed}
/>
)}
{ownedChannel && (
<Button
style={channelPageStyle.deleteButton}
theme={'light'}
icon={'trash-alt'}
text={'Delete'}
onPress={this.onDeletePressed}
/>
)}
{!ownedChannel && <SubscribeButton style={channelPageStyle.subscribeButton} uri={fullUri} name={name} />}
{!ownedChannel && (
<SubscribeNotificationButton
style={[channelPageStyle.subscribeButton, channelPageStyle.bellButton]}
uri={fullUri}
name={name}
/>
)}
</View>
</View>

View file

@ -0,0 +1,49 @@
import { connect } from 'react-redux';
import {
selectAbandoningIds,
selectBalance,
selectMyChannelClaims,
selectFetchingMyChannels,
selectUpdatingChannel,
selectUpdateChannelError,
doAbandonClaim,
doFetchChannelListMine,
doCreateChannel,
doUpdateChannel,
doToast,
} from 'lbry-redux';
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import { doUpdateChannelFormState, doClearChannelFormState } from 'redux/actions/form';
import { selectDrawerStack } from 'redux/selectors/drawer';
import { selectChannelFormState } from 'redux/selectors/form';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import ChannelCreator from './view';
const select = state => ({
abandoningClaimIds: selectAbandoningIds(state),
channels: selectMyChannelClaims(state),
channelFormState: selectChannelFormState(state),
drawerStack: selectDrawerStack(state),
fetchingChannels: selectFetchingMyChannels(state),
balance: selectBalance(state),
updatingChannel: selectUpdatingChannel(state),
updateChannelError: selectUpdateChannelError(state),
});
const perform = dispatch => ({
abandonClaim: (txid, nout) => dispatch(doAbandonClaim(txid, nout)),
notify: data => dispatch(doToast(data)),
clearChannelFormState: () => dispatch(doClearChannelFormState()),
createChannel: (name, amount, optionalParams) => dispatch(doCreateChannel(name, amount, optionalParams)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
updateChannel: params => dispatch(doUpdateChannel(params)),
updateChannelFormState: data => dispatch(doUpdateChannelFormState(data)),
pushDrawerStack: (routeName, params) => dispatch(doPushDrawerStack(routeName, params)),
popDrawerStack: () => dispatch(doPopDrawerStack()),
setPlayerVisible: () => dispatch(doSetPlayerVisible(false)),
});
export default connect(
select,
perform
)(ChannelCreator);

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import { connect } from 'react-redux';
import {
doFetchFileInfo,
doFetchChannelListMine,
doFetchClaimListMine,
doFileGet,
doPurchaseUri,
@ -19,6 +20,7 @@ import {
makeSelectThumbnailForUri,
makeSelectTitleForUri,
selectBalance,
selectMyChannelClaims,
selectMyClaimUrisWithoutChannels,
selectPurchasedUris,
selectFailedPurchaseUris,
@ -46,6 +48,7 @@ const select = (state, props) => {
return {
balance: selectBalance(state),
blackListedOutpoints: selectBlackListedOutpoints(state),
channels: selectMyChannelClaims(state),
claim: makeSelectClaimForUri(selectProps.uri)(state),
drawerStack: selectDrawerStack(state),
isResolvingUri: makeSelectIsUriResolving(selectProps.uri)(state),
@ -75,6 +78,7 @@ const perform = dispatch => ({
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
fetchMyClaims: () => dispatch(doFetchClaimListMine()),
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
fileGet: (uri, saveFile) => dispatch(doFileGet(uri, saveFile)),
notify: data => dispatch(doToast(data)),
popDrawerStack: () => dispatch(doPopDrawerStack()),

View file

@ -1,5 +1,5 @@
import React from 'react';
import { Lbry, normalizeURI } from 'lbry-redux';
import { Lbry, normalizeURI, parseURI } from 'lbry-redux';
import { Lbryio } from 'lbryinc';
import {
ActivityIndicator,
@ -100,7 +100,7 @@ class FilePage extends React.PureComponent {
DeviceEventEmitter.addListener('onDownloadUpdated', this.handleDownloadUpdated);
DeviceEventEmitter.addListener('onDownloadCompleted', this.handleDownloadCompleted);
const { fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
const { fetchChannelListMine, fileInfo, isResolvingUri, resolveUri, navigation } = this.props;
const { uri, uriVars } = navigation.state.params;
this.setState({ uri, uriVars });
@ -108,6 +108,7 @@ class FilePage extends React.PureComponent {
this.fetchFileInfo(this.props);
this.fetchCostInfo(this.props);
fetchChannelListMine();
if (NativeModules.Firebase) {
NativeModules.Firebase.track('open_file_page', { uri: uri });
@ -567,6 +568,7 @@ class FilePage extends React.PureComponent {
const {
balance,
claim,
channels,
channelUri,
costInfo,
fileInfo,
@ -585,6 +587,10 @@ class FilePage extends React.PureComponent {
} = this.props;
const { uri, autoplay } = navigation.state.params;
const myChannelUris = channels ? channels.map(channel => channel.permanent_url) : [];
const ownedClaim = myClaimUris.includes(uri) || myChannelUris.includes(uri);
const { isChannel } = parseURI(uri);
let innerContent = null;
if ((isResolvingUri && !claim) || !claim) {
return (
@ -597,7 +603,14 @@ class FilePage extends React.PureComponent {
)}
{claim === null && !isResolvingUri && (
<View style={filePageStyle.container}>
<Text style={filePageStyle.emptyClaimText}>There's nothing at this location.</Text>
{ownedClaim && (
<Text style={filePageStyle.emptyClaimText}>
{isChannel
? 'It looks like you just created this channel. It will appear in a few minutes.'
: 'It looks you just published this content. It will appear in a few minutes.'}
</Text>
)}
{!ownedClaim && <Text style={filePageStyle.emptyClaimText}>There's nothing at this location.</Text>}
</View>
)}
<UriBar value={uri} navigation={navigation} />
@ -606,7 +619,7 @@ class FilePage extends React.PureComponent {
}
if (claim) {
if (claim && claim.name.length && claim.name[0] === '@') {
if (isChannel) {
return <ChannelPage uri={uri} navigation={navigation} />;
}

View file

@ -523,6 +523,8 @@ class PublishPage extends React.PureComponent {
});
};
handleUploadPressed = () => {};
getRandomFileId = () => {
// generate a random id for a photo or recorded video between 1 and 20 (for creating thumbnails)
const id = Math.floor(Math.random() * (20 - 2)) + 1;
@ -824,6 +826,7 @@ class PublishPage extends React.PureComponent {
)}
<TextInput
editable={this.state.canPublish && !this.state.publishStarted}
multiline
placeholder={this.state.descriptionFocused ? '' : 'Description'}
style={publishStyle.inputText}
value={this.state.description}

View file

@ -33,6 +33,15 @@ class PublishesPage extends React.PureComponent {
this.onComponentFocused();
}
componentWillReceiveProps(nextProps) {
const { currentRoute } = nextProps;
const { currentRoute: prevRoute } = this.props;
if (Constants.DRAWER_ROUTE_PUBLISHES === currentRoute && currentRoute !== prevRoute) {
this.onComponentFocused();
}
}
onComponentFocused = () => {
const { checkPendingPublishes, fetchMyClaims, pushDrawerStack, setPlayerVisible } = this.props;
pushDrawerStack();

23
src/redux/actions/form.js Normal file
View file

@ -0,0 +1,23 @@
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
export const doUpdatePublishFormState = publishFormValue => dispatch =>
dispatch({
type: Constants.ACTION_UPDATE_PUBLISH_FORM_STATE,
data: { ...publishFormValue },
});
export const doUpdateChannelFormState = channelFormValue => dispatch =>
dispatch({
type: Constants.ACTION_UPDATE_CHANNEL_FORM_STATE,
data: { ...channelFormValue },
});
export const doClearPublishFormState = () => dispatch =>
dispatch({
type: Constants.ACTION_CLEAR_PUBLISH_FORM_STATE,
});
export const doClearChannelFormState = () => dispatch =>
dispatch({
type: Constants.ACTION_CLEAR_CHANNEL_FORM_STATE,
});

View file

@ -16,7 +16,19 @@ reducers[Constants.ACTION_PUSH_DRAWER_STACK] = (state, action) => {
const { routeName, params } = action.data;
const newStack = state.stack.slice();
if (routeName !== newStack[newStack.length - 1].route) {
const lastRoute = newStack[newStack.length - 1].route;
let canPushStack = routeName !== lastRoute;
if (
lastRoute === Constants.DRAWER_ROUTE_CHANNEL_CREATOR_FORM &&
routeName === Constants.DRAWER_ROUTE_CHANNEL_CREATOR
) {
canPushStack = false;
}
if (lastRoute === Constants.DRAWER_ROUTE_PUBLISH_FORM && routeName === Constants.DRAWER_ROUTE_PUBLISH) {
canPushStack = false;
}
if (canPushStack) {
newStack.push({ route: routeName, params });
}

View file

@ -0,0 +1,49 @@
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
const reducers = {};
const defaultState = {
channelFormValues: {},
publishFormValues: {},
};
reducers[Constants.ACTION_UPDATE_PUBLISH_FORM_STATE] = (state, action) => {
const { data } = action;
const publishFormValues = Object.assign({}, state.publishFormValues);
const newPublishFormValues = Object.assign(publishFormValues, data);
return {
...state,
publishFormValues: newPublishFormValues,
};
};
reducers[Constants.ACTION_UPDATE_CHANNEL_FORM_STATE] = (state, action) => {
const { data } = action;
const channelFormValues = Object.assign({}, state.channelFormValues);
const newChannelFormValues = Object.assign(channelFormValues, data);
return {
...state,
channelFormValues: newChannelFormValues,
};
};
reducers[Constants.ACTION_CLEAR_PUBLISH_FORM_STATE] = state => {
return {
...state,
publishFormValues: {},
};
};
reducers[Constants.ACTION_CLEAR_CHANNEL_FORM_STATE] = state => {
return {
...state,
channelFormValues: {},
};
};
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
return state;
}

View file

@ -0,0 +1,13 @@
import { createSelector } from 'reselect';
export const selectState = state => state.form || {};
export const selectPublishFormState = createSelector(
selectState,
state => state.publishFormValues || {}
);
export const selectChannelFormState = createSelector(
selectState,
state => state.channelFormValues || {}
);

View file

@ -4,6 +4,9 @@ const autothumbStyle = StyleSheet.create({
autothumbPurple: {
backgroundColor: '#9c27b0',
},
autothumbDeepPurple: {
backgroundColor: '#5e35b1',
},
autothumbRed: {
backgroundColor: '#e53935',
},
@ -34,6 +37,21 @@ const autothumbStyle = StyleSheet.create({
autothumbOrange: {
backgroundColor: '#ffa726',
},
autothumbAmber: {
backgroundColor: '#ffb300',
},
autothumbLime: {
backgroundColor: '#c0ca33',
},
autothumbLightGreen: {
backgroundColor: '#7cb342',
},
autothumbDeepOrange: {
backgroundColor: '#f4511e',
},
autothumbBrown: {
backgroundColor: '#6d4c41',
},
});
export default autothumbStyle;

View file

@ -0,0 +1,261 @@
import { Dimensions, StyleSheet } from 'react-native';
import Colors from './colors';
const screenDimension = Dimensions.get('window');
const screenWidth = screenDimension.width;
const channelCreatorStyle = StyleSheet.create({
card: {
backgroundColor: Colors.White,
marginTop: 16,
marginLeft: 16,
marginRight: 16,
padding: 16,
},
container: {
flex: 1,
backgroundColor: Colors.PageBackground,
},
channelPicker: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
height: 52,
width: '100%',
},
bidRow: {
flexDirection: 'row',
alignItems: 'center',
},
label: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
},
channelNameInput: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
paddingLeft: 20,
},
bidAmountInput: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
marginLeft: 16,
textAlign: 'right',
width: 80,
},
helpText: {
fontFamily: 'Inter-UI-Regular',
fontSize: 12,
},
channelTitleInput: {
marginBottom: 4,
},
createChannelContainer: {
marginTop: 60,
flex: 1,
},
channelAt: {
position: 'absolute',
left: 4,
top: 13,
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
},
buttonContainer: {
marginTop: 24,
marginBottom: 16,
},
buttons: {
marginLeft: 16,
marginRight: 16,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
cancelLink: {
marginRight: 16,
},
createButton: {
backgroundColor: Colors.LbryGreen,
alignSelf: 'flex-end',
},
inlineError: {
fontFamily: 'Inter-UI-Regular',
fontSize: 12,
color: Colors.Red,
marginTop: 2,
},
imageSelectors: {
width: '100%',
height: 160,
},
coverImageTouchArea: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
},
coverImage: {
width: '100%',
height: '100%',
},
avatarImageContainer: {
position: 'absolute',
left: screenWidth / 2 - 80 / 2,
bottom: -16,
width: 80,
height: 80,
borderRadius: 160,
overflow: 'hidden',
},
avatarTouchArea: {
width: 80,
height: 80,
alignItems: 'center',
justifyContent: 'center',
},
avatarImage: {
width: '100%',
height: '100%',
},
listFooter: {
marginTop: 24,
},
createChannelButton: {
backgroundColor: Colors.LbryGreen,
alignSelf: 'flex-start',
},
scrollContainer: {
marginTop: 60,
marginLeft: 16,
marginRight: 16,
},
scrollPadding: {
paddingTop: 16,
},
channelListItem: {
flexDirection: 'row',
marginBottom: 16,
alignItems: 'center',
},
channelListTitle: {
fontFamily: 'Inter-UI-Regular',
fontSize: 18,
marginBottom: 4,
},
channelListName: {
fontFamily: 'Inter-UI-Regular',
fontSize: 14,
},
channelListAvatar: {
marginRight: 16,
width: 80,
height: 80,
borderRadius: 160,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
},
selectedOverlay: {
position: 'absolute',
left: 0,
top: 0,
width: 80,
height: 80,
borderRadius: 160,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000000aa',
},
listHeader: {
alignItems: 'center',
marginTop: 16,
marginBottom: 16,
},
textInputLayout: {
marginBottom: 4,
},
textInputTitle: {
fontFamily: 'Inter-UI-Regular',
fontSize: 12,
marginBottom: -10,
marginLeft: 4,
},
inputText: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
},
toggleContainer: {
marginTop: 24,
alignItems: 'center',
justifyContent: 'flex-end',
},
modeLink: {
color: Colors.LbryGreen,
alignSelf: 'flex-end',
marginRight: 16,
},
cardTitle: {
fontFamily: 'Inter-UI-Regular',
fontSize: 20,
marginBottom: 8,
},
tag: {
marginRight: 4,
marginBottom: 4,
},
tagList: {
flexDirection: 'row',
flexWrap: 'wrap',
},
editOverlay: {
alignItems: 'center',
justifyContent: 'center',
borderRadius: 24,
position: 'absolute',
padding: 8,
left: 4,
bottom: 4,
backgroundColor: '#00000077',
},
thumbnailEditOverlay: {
alignItems: 'center',
justifyContent: 'center',
borderRadius: 24,
position: 'absolute',
padding: 8,
left: 80 / 2 - 32 / 2,
bottom: 4,
backgroundColor: '#00000077',
},
editIcon: {
color: Colors.White,
fontFamily: 'Inter-UI-SemiBold',
fontSize: 12,
},
uploadProgress: {
alignItems: 'center',
borderRadius: 16,
flexDirection: 'row',
position: 'absolute',
top: 8,
right: 8,
backgroundColor: '#00000077',
paddingLeft: 8,
paddingRight: 8,
paddingTop: 4,
paddingBottom: 4,
justifyContent: 'center',
},
uploadText: {
color: Colors.White,
fontFamily: 'Inter-UI-SemiBold',
fontSize: 12,
marginLeft: 4,
},
});
export default channelCreatorStyle;

View file

@ -31,6 +31,7 @@ const channelPageStyle = StyleSheet.create({
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 24,
},
infoText: {
fontFamily: 'Inter-UI-Regular',
@ -165,6 +166,9 @@ const channelPageStyle = StyleSheet.create({
claimListContent: {
paddingTop: 16,
},
actionButton: {
backgroundColor: Colors.White,
},
});
export default channelPageStyle;

View file

@ -41,8 +41,8 @@ const filePageStyle = StyleSheet.create({
fontFamily: 'Inter-UI-Regular',
textAlign: 'center',
fontSize: 20,
marginLeft: 16,
marginRight: 16,
marginLeft: 24,
marginRight: 24,
},
scrollContainer: {
flex: 1,

View file

@ -156,6 +156,10 @@ const publishStyle = StyleSheet.create({
fontSize: 16,
marginLeft: 8,
},
listEmptyText: {
fontFamily: 'Inter-UI-Regular',
fontSize: 14,
},
titleRow: {
flexDirection: 'row',
justifyContent: 'space-between',

View file

@ -1,7 +1,7 @@
import { NavigationActions, StackActions } from 'react-navigation';
import { buildURI, isURIValid, normalizeURI } from 'lbry-redux';
import { doPopDrawerStack, doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
import Constants, { DrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api
import Constants, { DrawerRoutes, InnerDrawerRoutes } from 'constants'; // eslint-disable-line node/no-deprecated-api
const tagNameLength = 10;
@ -156,10 +156,26 @@ export function navigateBack(navigation, drawerStack, popDrawerStack) {
const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route, params } = target;
navigation.goBack(navigation.state.key);
if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
if (!DrawerRoutes.includes(route) && !InnerDrawerRoutes.includes(route) && isURIValid(route)) {
navigateToUri(navigation, route, null, true);
} else {
navigation.navigate({ routeName: route, params });
let targetRoute = route;
let targetParams = params;
if (InnerDrawerRoutes.includes(route)) {
if (Constants.DRAWER_ROUTE_CHANNEL_CREATOR_FORM === route) {
targetRoute = Constants.DRAWER_ROUTE_CHANNEL_CREATOR;
} else if (Constants.DRAWER_ROUTE_PUBLISH_FORM === route) {
targetRoute = Constants.DRAWER_ROUTE_PUBLISH_FORM;
}
if (targetParams) {
targetParams.displayForm = true;
} else {
targetParams = { displayForm: true };
}
}
navigation.navigate({ routeName: targetRoute, targetParams });
}
}
@ -169,14 +185,31 @@ export function dispatchNavigateBack(dispatch, nav, drawerStack) {
const target = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
const { route } = target;
dispatch(NavigationActions.back());
if (DrawerRoutes.indexOf(route) === -1 && isURIValid(route)) {
if (!DrawerRoutes.includes(route) && !InnerDrawerRoutes.includes(route) && isURIValid(route)) {
dispatchNavigateToUri(dispatch, nav, route, true);
} else {
const newTarget = drawerStack[drawerStack.length > 1 ? drawerStack.length - 2 : 0];
let targetRoute = newTarget.route;
let targetParams = newTarget.params;
if (InnerDrawerRoutes.includes(targetRoute)) {
if (Constants.DRAWER_ROUTE_CHANNEL_CREATOR_FORM === route) {
targetRoute = Constants.DRAWER_ROUTE_CHANNEL_CREATOR;
} else if (Constants.DRAWER_ROUTE_PUBLISH_FORM === route) {
targetRoute = Constants.DRAWER_ROUTE_PUBLISH_FORM;
}
if (targetParams) {
targetParams.displayForm = true;
} else {
targetParams = { displayForm: true };
}
}
const navigateAction = NavigationActions.navigate({
routeName: newTarget.route,
params: newTarget.params,
routeName: targetRoute,
params: targetParams,
});
dispatch(navigateAction);
}
}
@ -256,3 +289,42 @@ export function transformUrl(url) {
export function __(str) {
return str;
}
export function uploadImageAsset(filePath, success, failure) {
const makeid = () => {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 24; i += 1) text += possible.charAt(Math.floor(Math.random() * 62));
return text;
};
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
let fileExt = fileName.indexOf('.') > -1 ? fileName.substring(fileName.lastIndexOf('.') + 1).trim() : 0;
if (!fileExt) {
fileExt = 'jpg'; // default to jpg
}
const fileType = `image/${fileExt}`;
const data = new FormData();
const name = makeid();
data.append('name', name);
data.append('file', { uri: 'file://' + filePath, type: fileType, name: fileName });
return fetch('https://spee.ch/api/claim/publish', {
method: 'POST',
body: data,
})
.then(response => response.json())
.then(json => {
if (json.success) {
if (success) {
success({ url: `${json.data.url}.${fileExt}` });
}
}
})
.catch(err => {
if (failure) {
failure(err.message ? err.message : 'The image failed to upload.');
}
});
}