diff --git a/app/package.json b/app/package.json index 491c967d..555a398e 100644 --- a/app/package.json +++ b/app/package.json @@ -23,6 +23,7 @@ "react-native-image-zoom-viewer": "^2.2.5", "react-native-password-strength-meter": "^0.0.2", "react-native-phone-input": "lbryio/react-native-phone-input", + "react-native-super-grid": "^3.0.4", "react-native-vector-icons": "^6.4.2", "react-native-video": "lbryio/react-native-video#exoplayer-lbry-android", "react-navigation": "^3.11.0", diff --git a/app/src/component/AppNavigator.js b/app/src/component/AppNavigator.js index 9ca1c955..aa644c56 100644 --- a/app/src/component/AppNavigator.js +++ b/app/src/component/AppNavigator.js @@ -5,6 +5,7 @@ import DownloadsPage from 'page/downloads'; import DrawerContent from 'component/drawerContent'; import FilePage from 'page/file'; import FirstRunScreen from 'page/firstRun'; +import PublishPage from 'page/publish'; import RewardsPage from 'page/rewards'; import TrendingPage from 'page/trending'; import SearchPage from 'page/search'; @@ -133,6 +134,9 @@ const drawer = createDrawerNavigator({ WalletStack: { screen: walletStack, navigationOptions: { title: 'Wallet', drawerIcon: ({ tintColor }) => }}, + Publish: { screen: PublishPage, navigationOptions: { + drawerIcon: ({ tintColor }) => + }}, Rewards: { screen: RewardsPage, navigationOptions: { drawerIcon: ({ tintColor }) => }}, diff --git a/app/src/component/gallery/index.js b/app/src/component/gallery/index.js new file mode 100644 index 00000000..c942e248 --- /dev/null +++ b/app/src/component/gallery/index.js @@ -0,0 +1,4 @@ +import { connect } from 'react-redux'; +import Gallery from './view'; + +export default connect()(Gallery); diff --git a/app/src/component/gallery/view.js b/app/src/component/gallery/view.js new file mode 100644 index 00000000..d45e756c --- /dev/null +++ b/app/src/component/gallery/view.js @@ -0,0 +1,9 @@ +import React from 'react'; + +class Gallery extends React.PureComponent { + render() { + + } +} + +export default Gallery; diff --git a/app/src/constants.js b/app/src/constants.js index a48197e7..ccd0584f 100644 --- a/app/src/constants.js +++ b/app/src/constants.js @@ -48,6 +48,7 @@ const Constants = { DRAWER_ROUTE_TRENDING: "Trending", DRAWER_ROUTE_SUBSCRIPTIONS: "Subscriptions", DRAWER_ROUTE_MY_LBRY: "Downloads", + DRAWER_ROUTE_PUBLISH: "Publish", DRAWER_ROUTE_REWARDS: "Rewards", DRAWER_ROUTE_WALLET: "Wallet", DRAWER_ROUTE_SETTINGS: "Settings", diff --git a/app/src/page/publish/index.js b/app/src/page/publish/index.js new file mode 100644 index 00000000..5b5ff94c --- /dev/null +++ b/app/src/page/publish/index.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; +import { doToast } from 'lbry-redux'; +import { doPushDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer'; +import Constants from 'constants'; +import PublishPage from './view'; + +const perform = dispatch => ({ + notify: data => dispatch(doToast(data)), + pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_PUBLISH)), + setPlayerVisible: () => dispatch(doSetPlayerVisible(false)) +}); + +export default connect(null, perform)(PublishPage); \ No newline at end of file diff --git a/app/src/page/publish/view.js b/app/src/page/publish/view.js new file mode 100644 index 00000000..ce6eb0c9 --- /dev/null +++ b/app/src/page/publish/view.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { NativeModules, Text, View } from 'react-native'; +import publishStyle from 'styles/reward'; + +class PublishPage extends React.PureComponent { + didFocusListener; + + componentWillMount() { + const { navigation } = this.props; + this.didFocusListener = navigation.addListener('didFocus', this.onComponentFocused); + } + + componentWillUnmount() { + if (this.didFocusListener) { + this.didFocusListener.remove(); + } + } + + onComponentFocused = () => { + const { pushDrawerStack, setPlayerVisible } = this.props; + + pushDrawerStack(); + setPlayerVisible(); + NativeModules.Gallery.getVideos().then(videos => { + console.log('videos retrieved.'); + }); + } + + componentDidMount() { + this.onComponentFocused(); + } + + componentWillReceiveProps(nextProps) { + const { currentRoute } = nextProps; + const { currentRoute: prevRoute } = this.props; + + if (Constants.DRAWER_ROUTE_REWARDS === currentRoute && currentRoute !== prevRoute) { + this.onComponentFocused(); + } + } + + render() { + return ( + + + + + ); + } +} + +export default PublishPage; diff --git a/app/src/styles/publish.js b/app/src/styles/publish.js new file mode 100644 index 00000000..eeb87737 --- /dev/null +++ b/app/src/styles/publish.js @@ -0,0 +1,11 @@ +import { StyleSheet } from 'react-native'; +import Colors from './colors'; + +const publishStyle = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: Colors.PageBackground + } +}); + +export default publishStyle; diff --git a/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java b/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java new file mode 100644 index 00000000..b3eb24bf --- /dev/null +++ b/src/main/java/io/lbry/browser/reactmodules/GalleryModule.java @@ -0,0 +1,146 @@ +package io.lbry.browser.reactmodules; + +import android.content.Context; +import android.database.Cursor; +import android.provider.MediaStore; +import android.os.Bundle; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; + +import java.util.List; +import java.util.ArrayList; + +public class GalleryModule extends ReactContextBaseJavaModule { + private Context context; + + public GalleryModule(ReactApplicationContext reactContext) { + super(reactContext); + this.context = reactContext; + } + + @Override + public String getName() { + return "Gallery"; + } + + @ReactMethod + public void getVideos(Promise promise) { + WritableArray items = Arguments.createArray(); + List videos = loadVideos(); + for (int i = 0; i < videos.size(); i++) { + items.pushMap(videos.get(i).toMap()); + } + + promise.resolve(items); + } + + private List loadVideos() { + String[] projection = { + MediaStore.MediaColumns._ID, + MediaStore.MediaColumns.DATA, + MediaStore.MediaColumns.DISPLAY_NAME, + MediaStore.MediaColumns.MIME_TYPE, + MediaStore.Video.Media.DURATION + }; + + List items = new ArrayList(); + Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null); + while (cursor.moveToNext()) { + int idColumn = cursor.getColumnIndex(MediaStore.MediaColumns._ID); + int nameColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME); + int typeColumn = cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE); + int pathColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DATA); + int durationColumn = cursor.getColumnIndex(MediaStore.Video.Media.DURATION); + + GalleryItem item = new GalleryItem(); + item.setId(cursor.getString(idColumn)); + item.setName(cursor.getString(nameColumn)); + item.setType(cursor.getString(typeColumn)); + item.setFilePath(cursor.getString(pathColumn)); + items.add(item); + } + + return items; + } + + + private static class GalleryItem { + private String id; + + private int duration; + + private String filePath; + + private String name; + + private String thumbnailUri; + + private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getThumbnailUri() { + return thumbnailUri; + } + + public void setThumnbailUri(String thumbnailUri) { + this.thumbnailUri = thumbnailUri; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public WritableMap toMap() { + WritableMap map = Arguments.createMap(); + map.putString("id", id); + map.putString("name", name); + map.putString("filePath", filePath); + map.putString("type", type); + map.putString("thumbnailUri", thumbnailUri); + map.putInt("duration", duration); + + return map; + } + } +} diff --git a/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java b/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java index e6191344..6b535bae 100644 --- a/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java +++ b/src/main/java/io/lbry/browser/reactpackages/LbryReactPackage.java @@ -9,6 +9,7 @@ import io.lbry.browser.reactmodules.BackgroundMediaModule; import io.lbry.browser.reactmodules.DaemonServiceControlModule; import io.lbry.browser.reactmodules.FirstRunModule; import io.lbry.browser.reactmodules.FirebaseModule; +import io.lbry.browser.reactmodules.GalleryModule; import io.lbry.browser.reactmodules.ScreenOrientationModule; import io.lbry.browser.reactmodules.VersionInfoModule; import io.lbry.browser.reactmodules.UtilityModule;; @@ -31,6 +32,7 @@ public class LbryReactPackage implements ReactPackage { modules.add(new DaemonServiceControlModule(reactContext)); modules.add(new FirstRunModule(reactContext)); modules.add(new FirebaseModule(reactContext)); + modules.add(new GalleryModule(reactContext)); modules.add(new ScreenOrientationModule(reactContext)); modules.add(new UtilityModule(reactContext)); modules.add(new VersionInfoModule(reactContext));