First run timing (#83)

* first run time tracking implementation
* Fix values in AsyncStorage calls. Some tweaks to Mixpanel event properties.
* remove first launch related items in AsyncStorage after final retrieval
This commit is contained in:
akinwale 2018-04-24 20:32:17 +01:00 committed by GitHub
parent 77a86da984
commit 90d17604fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 18 deletions

View file

@ -8,6 +8,7 @@
},
"dependencies": {
"lbry-redux": "lbryio/lbry-redux",
"moment": "^2.22.1",
"react": "16.2.0",
"react-native": "0.52.0",
"react-native-vector-icons": "^4.5.0",

View file

@ -14,7 +14,13 @@ import {
} from 'react-navigation';
import { connect } from 'react-redux';
import { addListener } from '../utils/redux';
import { AppState, BackHandler, NativeModules, TextInput } from 'react-native';
import {
AppState,
AsyncStorage,
BackHandler,
NativeModules,
TextInput
} from 'react-native';
import { SETTINGS } from 'lbry-redux';
import { makeSelectClientSetting } from '../redux/selectors/settings';
import Feather from 'react-native-vector-icons/Feather';
@ -102,16 +108,16 @@ class AppWithNavigationState extends React.Component {
}
_handleAppStateChange = (nextAppState) => {
// this is properly handled in native code at the moment
/*const { keepDaemonRunning } = this.props;
if (AppState.currentState &&
AppState.currentState.match(/inactive|background/) &&
NativeModules.DaemonServiceControl) {
if (!keepDaemonRunning) {
// terminate the daemon background service when is suspended / inactive
//NativeModules.DaemonServiceControl.stopService();
}
}*/
// Check if the app was suspended
if (AppState.currentState && AppState.currentState.match(/inactive|background/)) {
AsyncStorage.getItem('firstLaunchTime').then(start => {
if (start !== null && !isNaN(parseInt(start, 10))) {
// App suspended during first launch?
// If so, this needs to be included as a property when tracking
AsyncStorage.setItem('firstLaunchSuspended', 'true');
}
});
}
}
render() {

View file

@ -61,7 +61,7 @@ class FileDownloadButton extends React.PureComponent {
return (
<TouchableOpacity style={[style, fileDownloadButtonStyle.container]} onPress={() => {
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Purchase Uri', { uri });
NativeModules.Mixpanel.track('Purchase Uri', { Uri: uri });
}
purchaseUri(uri);
}}>

View file

@ -59,7 +59,7 @@ class FileItem extends React.PureComponent {
<View style={style}>
<TouchableOpacity style={discoverStyle.container} onPress={() => {
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Tap', { uri });
NativeModules.Mixpanel.track('Discover Tap', { Uri: uri });
}
navigation.navigate('File', { uri: uri });
}

View file

@ -85,7 +85,7 @@ class MediaPlayer extends React.PureComponent {
if (this.state.firstPlay) {
if (NativeModules.Mixpanel) {
const { uri } = this.props;
NativeModules.Mixpanel.track('Play', { uri });
NativeModules.Mixpanel.track('Play', { Uri: uri });
}
this.setState({ firstPlay: false });
this.hidePlayerControls();

View file

@ -6,7 +6,7 @@ import SearchInput from './view';
const perform = dispatch => ({
search: search => {
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Search', { query: search });
NativeModules.Mixpanel.track('Search', { Query: search });
}
return dispatch(doSearch(search));
},

View file

@ -1,7 +1,14 @@
import React from 'react';
import { Provider, connect } from 'react-redux';
import DiscoverPage from './page/discover';
import { AppRegistry, AppState, StyleSheet, Text, View, AsyncStorage, NativeModules } from 'react-native';
import {
AppRegistry,
AppState,
AsyncStorage,
Text,
View,
NativeModules
} from 'react-native';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import {
StackNavigator, addNavigationHelpers
@ -21,6 +28,7 @@ import {
walletReducer
} from 'lbry-redux';
import settingsReducer from './redux/reducers/settings';
import moment from 'moment';
import { reactNavigationMiddleware } from './utils/redux';
function isFunction(object) {
@ -105,6 +113,16 @@ persistStore(store, persistOptions, err => {
});
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() {
return (
<Provider store={store}>

View file

@ -1,12 +1,35 @@
import React from 'react';
import FeaturedCategory from '../../component/featuredCategory';
import NavigationActions from 'react-navigation';
import { Text, View, ScrollView } from 'react-native';
import { AsyncStorage, NativeModules, ScrollView, Text, View } from 'react-native';
import moment from 'moment';
import discoverStyle from '../../styles/discover';
import Feather from 'react-native-vector-icons/Feather';
class DiscoverPage extends React.PureComponent {
componentWillMount() {
// Track the total time taken if this is the first launch
AsyncStorage.getItem('firstLaunchTime').then(startTime => {
if (startTime !== null && !isNaN(parseInt(startTime, 10))) {
// We don't need this value anymore once we've retrieved it
AsyncStorage.removeItem('firstLaunchTime');
// We know this is the first app launch because firstLaunchTime is set and it's a valid number
const start = parseInt(startTime, 10);
const now = moment().unix();
const delta = now - start;
AsyncStorage.getItem('firstLaunchSuspended').then(suspended => {
AsyncStorage.removeItem('firstLaunchSuspended');
const appSuspended = (suspended === 'true');
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('First Run Time', {
'Total Seconds': delta, 'App Suspended': appSuspended
});
}
});
}
});
this.props.fetchFeaturedUris();
}

View file

@ -33,7 +33,7 @@ class FilePage extends React.PureComponent {
this.fetchFileInfo(this.props);
this.fetchCostInfo(this.props);
if (NativeModules.Mixpanel) {
NativeModules.Mixpanel.track('Open File Page', { uri: this.props.navigation.state.params.uri });
NativeModules.Mixpanel.track('Open File Page', { Uri: this.props.navigation.state.params.uri });
}
}