Merge pull request #166 from lbryio/first-run-improvements
implement extendable first run experience starting with welcome page
This commit is contained in:
commit
31168d9ed8
19 changed files with 333 additions and 78 deletions
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import AboutPage from '../page/about';
|
import AboutPage from '../page/about';
|
||||||
import DiscoverPage from '../page/discover';
|
import DiscoverPage from '../page/discover';
|
||||||
import FilePage from '../page/file';
|
import FilePage from '../page/file';
|
||||||
|
import FirstRunScreen from '../page/firstRun';
|
||||||
import SearchPage from '../page/search';
|
import SearchPage from '../page/search';
|
||||||
import TrendingPage from '../page/trending';
|
import TrendingPage from '../page/trending';
|
||||||
import SettingsPage from '../page/settings';
|
import SettingsPage from '../page/settings';
|
||||||
|
@ -99,6 +100,12 @@ const drawer = DrawerNavigator({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AppNavigator = new StackNavigator({
|
export const AppNavigator = new StackNavigator({
|
||||||
|
FirstRun: {
|
||||||
|
screen: FirstRunScreen,
|
||||||
|
navigationOptions: {
|
||||||
|
drawerLockMode: 'locked-closed'
|
||||||
|
}
|
||||||
|
},
|
||||||
Splash: {
|
Splash: {
|
||||||
screen: SplashScreen,
|
screen: SplashScreen,
|
||||||
navigationOptions: {
|
navigationOptions: {
|
||||||
|
|
|
@ -61,7 +61,7 @@ function enableBatching(reducer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = AppNavigator.router;
|
const router = AppNavigator.router;
|
||||||
const navAction = router.getActionForPathAndParams('Splash');
|
const navAction = router.getActionForPathAndParams('FirstRun');
|
||||||
const initialNavState = router.getStateForAction(navAction);
|
const initialNavState = router.getStateForAction(navAction);
|
||||||
const navigatorReducer = (state = initialNavState, action) => {
|
const navigatorReducer = (state = initialNavState, action) => {
|
||||||
const nextState = AppNavigator.router.getStateForAction(action, state);
|
const nextState = AppNavigator.router.getStateForAction(action, state);
|
||||||
|
@ -116,16 +116,6 @@ persistStore(store, persistOptions, err => {
|
||||||
});
|
});
|
||||||
|
|
||||||
class LBRYApp extends React.Component {
|
class LBRYApp extends React.Component {
|
||||||
componentDidMount() {
|
|
||||||
AsyncStorage.getItem('hasLaunched').then(value => {
|
|
||||||
if (value == null || value !== 'true') {
|
|
||||||
AsyncStorage.setItem('hasLaunched', 'true');
|
|
||||||
// only set firstLaunchTime since we've determined that this is the first app launch ever
|
|
||||||
AsyncStorage.setItem('firstLaunchTime', String(moment().unix()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
|
6
app/src/page/firstRun/index.js
Normal file
6
app/src/page/firstRun/index.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import FirstRun from './view';
|
||||||
|
|
||||||
|
const perform = dispatch => ({});
|
||||||
|
|
||||||
|
export default connect(null, perform)(FirstRun);
|
21
app/src/page/firstRun/internal/welcome-page.js
Normal file
21
app/src/page/firstRun/internal/welcome-page.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import { View, Text, Linking } from 'react-native';
|
||||||
|
import Colors from '../../../styles/colors';
|
||||||
|
import firstRunStyle from '../../../styles/firstRun';
|
||||||
|
|
||||||
|
class WelcomePage extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.container}>
|
||||||
|
<Text style={firstRunStyle.title}>Welcome to LBRY.</Text>
|
||||||
|
<Text style={firstRunStyle.paragraph}>LBRY is a decentralized peer-to-peer content sharing platform where
|
||||||
|
you can upload and download videos, music, ebooks and other forms of digital content.</Text>
|
||||||
|
<Text style={firstRunStyle.paragraph}>We make use of a blockchain which needs to be synchronized before
|
||||||
|
you can use the app. Synchronization may take a while because this is the first app launch.</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WelcomePage;
|
96
app/src/page/firstRun/view.js
Normal file
96
app/src/page/firstRun/view.js
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
Linking,
|
||||||
|
NativeModules,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View
|
||||||
|
} from 'react-native';
|
||||||
|
import { NavigationActions } from 'react-navigation';
|
||||||
|
import Colors from '../../styles/colors';
|
||||||
|
import WelcomePage from './internal/welcome-page';
|
||||||
|
import firstRunStyle from '../../styles/firstRun';
|
||||||
|
|
||||||
|
class FirstRunScreen extends React.PureComponent {
|
||||||
|
static pages = ['welcome'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
currentPage: null,
|
||||||
|
launchUrl: null,
|
||||||
|
isFirstRun: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
Linking.getInitialURL().then((url) => {
|
||||||
|
if (url) {
|
||||||
|
this.setState({ launchUrl: url });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (NativeModules.FirstRun) {
|
||||||
|
NativeModules.FirstRun.isFirstRun().then(firstRun => {
|
||||||
|
this.setState({ isFirstRun: firstRun });
|
||||||
|
if (firstRun) {
|
||||||
|
this.setState({ currentPage: FirstRunScreen.pages[0] });
|
||||||
|
} else {
|
||||||
|
// Not the first run. Navigate to the splash screen right away
|
||||||
|
this.launchSplashScreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// The first run module was not detected. Go straight to the splash screen.
|
||||||
|
this.launchSplashScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launchSplashScreen() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
const resetAction = NavigationActions.reset({
|
||||||
|
index: 0,
|
||||||
|
actions: [
|
||||||
|
NavigationActions.navigate({ routeName: 'Splash', params: { launchUri: this.state.launchUri } })
|
||||||
|
]
|
||||||
|
});
|
||||||
|
navigation.dispatch(resetAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleContinuePressed = () => {
|
||||||
|
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
|
||||||
|
if (pageIndex === (FirstRunScreen.pages.length - 1)) {
|
||||||
|
// Final page. Let the app know that first run experience is completed.
|
||||||
|
if (NativeModules.FirstRun) {
|
||||||
|
NativeModules.FirstRun.firstRunCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to the splash screen
|
||||||
|
this.launchSplashScreen();
|
||||||
|
} else {
|
||||||
|
// TODO: Page transition animation?
|
||||||
|
this.state.currentPage = FirstRunScreen.pages[pageIndex + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let page = null;
|
||||||
|
if (this.state.currentPage === 'welcome') {
|
||||||
|
// show welcome page
|
||||||
|
page = (<WelcomePage />);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.screenContainer}>
|
||||||
|
{page}
|
||||||
|
{this.state.currentPage &&
|
||||||
|
<TouchableOpacity style={firstRunStyle.button} onPress={this.handleContinuePressed}>
|
||||||
|
<Text style={firstRunStyle.buttonText}>Continue</Text>
|
||||||
|
</TouchableOpacity>}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FirstRunScreen;
|
|
@ -1,8 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Lbry } from 'lbry-redux';
|
import { Lbry } from 'lbry-redux';
|
||||||
import { View, Text, Linking, NativeModules } from 'react-native';
|
import { ActivityIndicator, View, Text, Linking, NativeModules } from 'react-native';
|
||||||
import { NavigationActions } from 'react-navigation';
|
import { NavigationActions } from 'react-navigation';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import Colors from '../../styles/colors';
|
||||||
import splashStyle from '../../styles/splash';
|
import splashStyle from '../../styles/splash';
|
||||||
|
|
||||||
class SplashScreen extends React.PureComponent {
|
class SplashScreen extends React.PureComponent {
|
||||||
|
@ -18,6 +19,21 @@ class SplashScreen extends React.PureComponent {
|
||||||
isLagging: false,
|
isLagging: false,
|
||||||
launchUrl: null
|
launchUrl: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (NativeModules.DaemonServiceControl) {
|
||||||
|
NativeModules.DaemonServiceControl.startService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// Start measuring the first launch time from the splash screen (time from daemon start to user interaction)
|
||||||
|
AsyncStorage.getItem('hasLaunched').then(value => {
|
||||||
|
if (value == null || value !== 'true') {
|
||||||
|
AsyncStorage.setItem('hasLaunched', 'true');
|
||||||
|
// only set firstLaunchTime since we've determined that this is the first app launch ever
|
||||||
|
AsyncStorage.setItem('firstLaunchTime', String(moment().unix()));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStatus() {
|
updateStatus() {
|
||||||
|
@ -53,8 +69,9 @@ class SplashScreen extends React.PureComponent {
|
||||||
});
|
});
|
||||||
navigation.dispatch(resetAction);
|
navigation.dispatch(resetAction);
|
||||||
|
|
||||||
if (this.state.launchUrl) {
|
const launchUrl = navigation.state.params.launchUrl || this.state.launchUrl;
|
||||||
navigation.navigate({ routeName: 'File', key: this.state.launchUrl, params: { uri: this.state.launchUrl } });
|
if (launchUrl) {
|
||||||
|
navigation.navigate({ routeName: 'File', key: launchUrl, params: { uri: launchUrl } });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -111,6 +128,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<View style={splashStyle.container}>
|
<View style={splashStyle.container}>
|
||||||
<Text style={splashStyle.title}>LBRY</Text>
|
<Text style={splashStyle.title}>LBRY</Text>
|
||||||
|
<ActivityIndicator color={Colors.White} style={splashStyle.loading} size={"small"} />
|
||||||
<Text style={splashStyle.message}>{message}</Text>
|
<Text style={splashStyle.message}>{message}</Text>
|
||||||
<Text style={splashStyle.details}>{details}</Text>
|
<Text style={splashStyle.details}>{details}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
44
app/src/styles/firstRun.js
Normal file
44
app/src/styles/firstRun.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import Colors from './colors';
|
||||||
|
|
||||||
|
const firstRunStyle = StyleSheet.create({
|
||||||
|
screenContainer: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: Colors.LbryGreen
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 9,
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: Colors.LbryGreen
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontFamily: 'Metropolis-SemiBold',
|
||||||
|
fontSize: 40,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32,
|
||||||
|
marginBottom: 32,
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 18,
|
||||||
|
lineHeight: 24,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32,
|
||||||
|
marginBottom: 20,
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
flex: 1,
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 28,
|
||||||
|
color: Colors.White
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default firstRunStyle;
|
|
@ -1,30 +1,34 @@
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
import Colors from './colors';
|
||||||
|
|
||||||
const splashStyle = StyleSheet.create({
|
const splashStyle = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
backgroundColor: '#40b89a'
|
backgroundColor: Colors.LbryGreen
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontFamily: 'Metropolis-Bold',
|
fontFamily: 'Metropolis-Bold',
|
||||||
fontSize: 64,
|
fontSize: 64,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: 48,
|
marginBottom: 48,
|
||||||
color: '#ffffff'
|
color: Colors.White
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
marginBottom: 36
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
fontFamily: 'Metropolis-Regular',
|
fontFamily: 'Metropolis-Regular',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
marginLeft: 16,
|
marginLeft: 16,
|
||||||
marginRight: 16,
|
marginRight: 16,
|
||||||
color: '#ffffff',
|
color: Colors.White,
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
fontFamily: 'Metropolis-Bold',
|
fontFamily: 'Metropolis-Bold',
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: '#ffffff',
|
color: Colors.White,
|
||||||
marginLeft: 16,
|
marginLeft: 16,
|
||||||
marginRight: 16,
|
marginRight: 16,
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
|
|
|
@ -36,7 +36,7 @@ version.filename = %(source.dir)s/main.py
|
||||||
|
|
||||||
# (list) Application requirements
|
# (list) Application requirements
|
||||||
# comma seperated e.g. requirements = sqlite3,kivy
|
# comma seperated e.g. requirements = sqlite3,kivy
|
||||||
requirements = openssl, sqlite3, hostpython2, android, pyjnius, certifi==2018.4.16, constantly, incremental, functools32, miniupnpc==1.9, gmpy==1.17, twisted==16.6.0, appdirs==1.4.3, argparse==1.2.1, docopt==0.6.2, base58==0.2.2, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse==0.2.0, jsonrpc==1.2, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2==1.3, pyyaml==3.12, qrcode==5.2.2, requests==2.9.1, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, slowaes==0.1a1, txJSON-RPC==0.5, wsgiref==0.1.2, zope.interface==4.3.3, protobuf==3.2.0, keyring==10.4.0, git+https://github.com/lbryio/lbryschema.git@v0.0.15#egg=lbryschema, git+https://github.com/lbryio/lbryum.git#egg=lbryum, git+https://github.com/lbryio/lbry.git#egg=lbrynet, asn1crypto, cryptography==2.2.2, pyopenssl==17.4.0, treq==17.8.0, funcsigs, mock, pbr, unqlite
|
requirements = openssl, sqlite3, hostpython2, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, functools32, miniupnpc==1.9, gmpy==1.17, twisted==16.6.0, appdirs==1.4.3, argparse==1.2.1, docopt==0.6.2, base58==0.2.2, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse==0.2.0, jsonrpc==1.2, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2==1.3, pyyaml==3.12, qrcode==5.2.2, requests==2.9.1, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, slowaes==0.1a1, txJSON-RPC==0.5, wsgiref==0.1.2, zope.interface==4.3.3, protobuf==3.2.0, keyring==10.4.0, git+https://github.com/lbryio/lbryschema.git@v0.0.15#egg=lbryschema, git+https://github.com/lbryio/lbryum.git#egg=lbryum, git+https://github.com/lbryio/lbry.git#egg=lbrynet, asn1crypto, cryptography==2.2.2, pyopenssl==17.4.0, treq==17.8.0, funcsigs, mock, pbr, unqlite
|
||||||
|
|
||||||
# (str) Custom source folders for requirements
|
# (str) Custom source folders for requirements
|
||||||
# Sets custom source for any requirements with recipes
|
# Sets custom source for any requirements with recipes
|
||||||
|
|
|
@ -36,7 +36,7 @@ version.filename = %(source.dir)s/main.py
|
||||||
|
|
||||||
# (list) Application requirements
|
# (list) Application requirements
|
||||||
# comma seperated e.g. requirements = sqlite3,kivy
|
# comma seperated e.g. requirements = sqlite3,kivy
|
||||||
requirements = openssl, sqlite3, hostpython2, android, pyjnius, certifi==2018.4.16, constantly, incremental, functools32, miniupnpc==1.9, gmpy==1.17, twisted==16.6.0, appdirs==1.4.3, argparse==1.2.1, docopt==0.6.2, base58==0.2.2, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse==0.2.0, jsonrpc==1.2, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2==1.3, pyyaml==3.12, qrcode==5.2.2, requests==2.9.1, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, slowaes==0.1a1, txJSON-RPC==0.5, wsgiref==0.1.2, zope.interface==4.3.3, protobuf==3.2.0, keyring==10.4.0, git+https://github.com/lbryio/lbryschema.git@v0.0.15#egg=lbryschema, git+https://github.com/lbryio/lbryum.git#egg=lbryum, git+https://github.com/lbryio/lbry.git#egg=lbrynet, asn1crypto, cryptography==2.2.2, pyopenssl==17.4.0, treq==17.8.0, funcsigs, mock, pbr, unqlite
|
requirements = openssl, sqlite3, hostpython2, android, distro, pyjnius, certifi==2018.4.16, constantly, incremental, functools32, miniupnpc==1.9, gmpy==1.17, twisted==16.6.0, appdirs==1.4.3, argparse==1.2.1, docopt==0.6.2, base58==0.2.2, colorama==0.3.7, dnspython==1.12.0, ecdsa==0.13, envparse==0.2.0, jsonrpc==1.2, jsonrpclib==0.1.7, jsonschema==2.5.1, pbkdf2==1.3, pyyaml==3.12, qrcode==5.2.2, requests==2.9.1, seccure==0.3.1.3, attrs==18.1.0, pyasn1, pyasn1-modules, service_identity==16.0.0, six==1.9.0, slowaes==0.1a1, txJSON-RPC==0.5, wsgiref==0.1.2, zope.interface==4.3.3, protobuf==3.2.0, keyring==10.4.0, git+https://github.com/lbryio/lbryschema.git@v0.0.15#egg=lbryschema, git+https://github.com/lbryio/lbryum.git#egg=lbryum, git+https://github.com/lbryio/lbry.git#egg=lbrynet, asn1crypto, cryptography==2.2.2, pyopenssl==17.4.0, treq==17.8.0, funcsigs, mock, pbr, unqlite
|
||||||
|
|
||||||
# (str) Custom source folders for requirements
|
# (str) Custom source folders for requirements
|
||||||
# Sets custom source for any requirements with recipes
|
# Sets custom source for any requirements with recipes
|
||||||
|
|
|
@ -380,6 +380,14 @@ main.py that loads it.''')
|
||||||
url_scheme=url_scheme,
|
url_scheme=url_scheme,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# add themes.xml
|
||||||
|
render(
|
||||||
|
'themes.tmpl.xml',
|
||||||
|
'src/main/res/values/themes.xml',
|
||||||
|
args=args,
|
||||||
|
url_scheme=url_scheme,
|
||||||
|
)
|
||||||
|
|
||||||
# add activity_service_control
|
# add activity_service_control
|
||||||
render(
|
render(
|
||||||
'activity_service_control.xml',
|
'activity_service_control.xml',
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
<application android:label="@string/app_name"
|
<application android:label="@string/app_name"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:theme="@android:style/Theme.Material.Light"
|
android:theme="@style/LbryAppTheme"
|
||||||
android:hardwareAccelerated="true">
|
android:hardwareAccelerated="true">
|
||||||
|
|
||||||
{% for m in args.meta_data %}
|
{% for m in args.meta_data %}
|
||||||
|
|
|
@ -6,4 +6,5 @@
|
||||||
|
|
||||||
<color name="red">#FF0000</color>
|
<color name="red">#FF0000</color>
|
||||||
<color name="green">#00C000</color>
|
<color name="green">#00C000</color>
|
||||||
|
<color name="lbrygreen">#40B89A</color>
|
||||||
</resources>
|
</resources>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<resources>
|
||||||
|
<style name="LbryAppTheme" parent="@android:style/Theme.Material.Light">
|
||||||
|
<item name="android:windowBackground">@color/lbrygreen</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -141,10 +141,15 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
SharedPreferences sp = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||||
|
if (!sp.getBoolean("firstRun", true)) {
|
||||||
|
// We're not showing the welcome page, so it's okay to start the daemon service
|
||||||
|
// because this is not the first run experience
|
||||||
serviceRunning = isServiceRunning(LbrynetService.class);
|
serviceRunning = isServiceRunning(LbrynetService.class);
|
||||||
if (!serviceRunning) {
|
if (!serviceRunning) {
|
||||||
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
|
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mReactInstanceManager != null) {
|
if (mReactInstanceManager != null) {
|
||||||
mReactInstanceManager.onHostResume(this, this);
|
mReactInstanceManager.onHostResume(this, this);
|
||||||
|
|
|
@ -24,6 +24,11 @@ public class DaemonServiceControlModule extends ReactContextBaseJavaModule {
|
||||||
return "DaemonServiceControl";
|
return "DaemonServiceControl";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void startService() {
|
||||||
|
ServiceHelper.start(context, "", LbrynetService.class, "lbrynetservice");
|
||||||
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void stopService() {
|
public void stopService() {
|
||||||
ServiceHelper.stop(context, LbrynetService.class);
|
ServiceHelper.stop(context, LbrynetService.class);
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package io.lbry.browser.reactmodules;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
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 io.lbry.browser.MainActivity;
|
||||||
|
|
||||||
|
public class FirstRunModule extends ReactContextBaseJavaModule {
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private SharedPreferences sp;
|
||||||
|
|
||||||
|
public FirstRunModule(ReactApplicationContext reactContext) {
|
||||||
|
super(reactContext);
|
||||||
|
this.context = reactContext;
|
||||||
|
this.sp = reactContext.getSharedPreferences(MainActivity.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "FirstRun";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void isFirstRun(final Promise promise) {
|
||||||
|
// If firstRun flag does not exist, default to true
|
||||||
|
boolean firstRun = sp.getBoolean("firstRun", true);
|
||||||
|
promise.resolve(firstRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void firstRunCompleted() {
|
||||||
|
SharedPreferences.Editor editor = sp.edit();
|
||||||
|
editor.putBoolean("firstRun", false);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,14 @@
|
||||||
package io.lbry.browser.reactmodules;
|
package io.lbry.browser.reactmodules;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Promise;
|
import com.facebook.react.bridge.Promise;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
import com.facebook.react.bridge.ReactMethod;
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
|
|
||||||
public class VersionInfoModule extends ReactContextBaseJavaModule {
|
public class VersionInfoModule extends ReactContextBaseJavaModule {
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.facebook.react.uimanager.ViewManager;
|
||||||
|
|
||||||
import io.lbry.browser.reactmodules.DaemonServiceControlModule;
|
import io.lbry.browser.reactmodules.DaemonServiceControlModule;
|
||||||
import io.lbry.browser.reactmodules.DownloadManagerModule;
|
import io.lbry.browser.reactmodules.DownloadManagerModule;
|
||||||
|
import io.lbry.browser.reactmodules.FirstRunModule;
|
||||||
import io.lbry.browser.reactmodules.MixpanelModule;
|
import io.lbry.browser.reactmodules.MixpanelModule;
|
||||||
import io.lbry.browser.reactmodules.ScreenOrientationModule;
|
import io.lbry.browser.reactmodules.ScreenOrientationModule;
|
||||||
import io.lbry.browser.reactmodules.VersionInfoModule;
|
import io.lbry.browser.reactmodules.VersionInfoModule;
|
||||||
|
@ -27,6 +28,7 @@ public class LbryReactPackage implements ReactPackage {
|
||||||
|
|
||||||
modules.add(new DaemonServiceControlModule(reactContext));
|
modules.add(new DaemonServiceControlModule(reactContext));
|
||||||
modules.add(new DownloadManagerModule(reactContext));
|
modules.add(new DownloadManagerModule(reactContext));
|
||||||
|
modules.add(new FirstRunModule(reactContext));
|
||||||
modules.add(new MixpanelModule(reactContext));
|
modules.add(new MixpanelModule(reactContext));
|
||||||
modules.add(new ScreenOrientationModule(reactContext));
|
modules.add(new ScreenOrientationModule(reactContext));
|
||||||
modules.add(new VersionInfoModule(reactContext));
|
modules.add(new VersionInfoModule(reactContext));
|
||||||
|
|
Loading…
Reference in a new issue