diff --git a/src/mobile/android/app/build.gradle b/src/mobile/android/app/build.gradle
index f3f3fd20ab..191912644f 100644
--- a/src/mobile/android/app/build.gradle
+++ b/src/mobile/android/app/build.gradle
@@ -92,7 +92,7 @@ android {
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "com.iota.trinity"
- versionCode 41
+ versionCode 42
versionName "0.6.1"
minSdkVersion 21
targetSdkVersion 26
diff --git a/src/mobile/ios/iotaWallet-tvOS/Info.plist b/src/mobile/ios/iotaWallet-tvOS/Info.plist
index 6ba8f8b118..f343b1a4da 100644
--- a/src/mobile/ios/iotaWallet-tvOS/Info.plist
+++ b/src/mobile/ios/iotaWallet-tvOS/Info.plist
@@ -19,7 +19,7 @@
CFBundleSignature
????
CFBundleVersion
- 41
+ 42
LSRequiresIPhoneOS
UILaunchStoryboardName
diff --git a/src/mobile/ios/iotaWallet-tvOSTests/Info.plist b/src/mobile/ios/iotaWallet-tvOSTests/Info.plist
index c7363ad129..cf3b3e3d16 100644
--- a/src/mobile/ios/iotaWallet-tvOSTests/Info.plist
+++ b/src/mobile/ios/iotaWallet-tvOSTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 41
+ 42
diff --git a/src/mobile/ios/iotaWallet.xcodeproj/project.pbxproj b/src/mobile/ios/iotaWallet.xcodeproj/project.pbxproj
index 6d1edbcbef..c099f2e455 100644
--- a/src/mobile/ios/iotaWallet.xcodeproj/project.pbxproj
+++ b/src/mobile/ios/iotaWallet.xcodeproj/project.pbxproj
@@ -2910,7 +2910,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = YES;
@@ -3305,7 +3305,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 42;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = YES;
FRAMEWORK_SEARCH_PATHS = (
diff --git a/src/mobile/ios/iotaWallet/Info.plist b/src/mobile/ios/iotaWallet/Info.plist
index 15b67428e4..9ba45d3e1f 100644
--- a/src/mobile/ios/iotaWallet/Info.plist
+++ b/src/mobile/ios/iotaWallet/Info.plist
@@ -25,7 +25,7 @@
CFBundleSignature
????
CFBundleVersion
- 41
+ 42
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/src/mobile/ios/iotaWalletTests/Info.plist b/src/mobile/ios/iotaWalletTests/Info.plist
index 2c142cde1a..7b7776f67e 100644
--- a/src/mobile/ios/iotaWalletTests/Info.plist
+++ b/src/mobile/ios/iotaWalletTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 41
+ 42
diff --git a/src/mobile/ios/iotaWalletUITests/Info.plist b/src/mobile/ios/iotaWalletUITests/Info.plist
index 19665b427c..c3a73854c0 100644
--- a/src/mobile/ios/iotaWalletUITests/Info.plist
+++ b/src/mobile/ios/iotaWalletUITests/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
0.6.1
CFBundleVersion
- 41
+ 42
diff --git a/src/mobile/src/ui/components/Migration.js b/src/mobile/src/ui/components/Migration.js
index 633bca690e..7dd657ddb4 100644
--- a/src/mobile/src/ui/components/Migration.js
+++ b/src/mobile/src/ui/components/Migration.js
@@ -1,4 +1,5 @@
import size from 'lodash/size';
+import sample from 'lodash/sampleSize';
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import PropTypes from 'prop-types';
@@ -8,13 +9,16 @@ import { startTrackingProgress } from 'shared-modules/actions/progress';
import { connect } from 'react-redux';
import { Styling } from 'ui/theme/general';
import { migrate } from 'shared-modules/actions/migrations';
+import { setFullNode } from 'shared-modules/actions/settings';
import { reduxPersistStorageAdapter } from 'libs/store';
import ProgressSteps from 'libs/progressSteps';
import { getThemeFromState } from 'shared-modules/selectors/global';
import Header from 'ui/components/Header';
import InfoBox from 'ui/components/InfoBox';
+import NotificationButtonComponent from 'ui/components/NotificationButton';
import ProgressBar from 'ui/components/OldProgressBar';
import { height } from 'libs/dimensions';
+import DualFooterButtons from './DualFooterButtons';
const styles = StyleSheet.create({
container: {
@@ -29,15 +33,25 @@ const styles = StyleSheet.create({
paddingTop: height / 16,
},
midContainer: {
- flex: 2.6,
+ flex: 1.9,
alignItems: 'center',
},
+ bottomContainer: {
+ flex: 0.7,
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ },
infoText: {
fontFamily: 'SourceSansPro-Light',
fontSize: Styling.fontSize3,
textAlign: 'left',
backgroundColor: 'transparent',
},
+ notificationButton: {
+ position: 'absolute',
+ top: height / 30 + Styling.statusBarHeight,
+ left: height / 30,
+ },
});
/**
@@ -59,11 +73,27 @@ class Migration extends Component {
startTrackingProgress: PropTypes.func.isRequired,
/** @ignore */
completedMigration: PropTypes.bool.isRequired,
+ /** @ignore */
+ notificationLog: PropTypes.array.isRequired,
+ /** @ignore */
+ nodes: PropTypes.array.isRequired,
+ /** @ignore */
+ setFullNode: PropTypes.func.isRequired,
+ /** @ignore */
+ isChangingNode: PropTypes.bool.isRequired,
};
+ constructor() {
+ super();
+ this.state = {
+ hasFailedMigration: false,
+ };
+ this.changeNode = this.changeNode.bind(this);
+ this.retryMigration = this.retryMigration.bind(this);
+ }
+
componentDidMount() {
this.props.startTrackingProgress(ProgressSteps.migration);
-
this.props.migrate(reduxPersistStorageAdapter);
}
@@ -71,6 +101,9 @@ class Migration extends Component {
if (!this.props.completedMigration && newProps.completedMigration) {
this.navigateToLoadingScreen();
}
+ if (size(this.props.notificationLog) !== size(newProps.notificationLog)) {
+ this.setState({ hasFailedMigration: true });
+ }
}
/**
@@ -107,6 +140,25 @@ class Migration extends Component {
});
}
+ /**
+ * Changes to a random node
+ *
+ * @method changeNode
+ */
+ changeNode() {
+ this.props.setFullNode(...sample(this.props.nodes));
+ }
+
+ /**
+ * Retries migration in case of failure
+ *
+ * @method retryMigration
+ */
+ retryMigration() {
+ this.setState({ hasFailedMigration: false });
+ this.props.migrate(reduxPersistStorageAdapter);
+ }
+
/**
* Renders progress bar textual information
*
@@ -119,7 +171,7 @@ class Migration extends Component {
}
render() {
- const { t, theme: { body, primary }, activeSteps, activeStepIndex } = this.props;
+ const { t, theme: { body, primary }, activeSteps, activeStepIndex, isChangingNode } = this.props;
const textColor = { color: body.color };
const sizeOfActiveSteps = size(activeSteps) - 1;
@@ -135,18 +187,36 @@ class Migration extends Component {
-
- {t(this.renderProgressBarChildren())}
-
+ {activeStepIndex > -1 && (
+
+ {t(this.renderProgressBarChildren())}
+
+ )}
+
+
+ {this.state.hasFailedMigration && (
+
+ )}
+ {this.state.hasFailedMigration && (
+
+
+
+ )}
);
}
@@ -157,11 +227,15 @@ const mapStateToProps = (state) => ({
activeStepIndex: state.progress.activeStepIndex,
activeSteps: state.progress.activeSteps,
completedMigration: state.settings.completedMigration,
+ notificationLog: state.alerts.notificationLog,
+ nodes: state.settings.nodes,
+ isChangingNode: state.ui.isChangingNode,
});
const mapDispatchToProps = {
migrate,
startTrackingProgress,
+ setFullNode,
};
export default withNamespaces(['migration'])(connect(mapStateToProps, mapDispatchToProps)(Migration));
diff --git a/src/mobile/src/ui/components/NotificationButton.js b/src/mobile/src/ui/components/NotificationButton.js
new file mode 100644
index 0000000000..e9b1381698
--- /dev/null
+++ b/src/mobile/src/ui/components/NotificationButton.js
@@ -0,0 +1,104 @@
+import size from 'lodash/size';
+import React, { Component } from 'react';
+import { StyleSheet, View, TouchableOpacity } from 'react-native';
+import { getThemeFromState } from 'shared-modules/selectors/global';
+import { clearLog } from 'shared-modules/actions/alerts';
+import { toggleModalActivity } from 'shared-modules/actions/ui';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { withNamespaces } from 'react-i18next';
+import { width } from 'libs/dimensions';
+import { Icon } from 'ui/theme/icons';
+
+const styles = StyleSheet.create({
+ container: {
+ width: width / 9,
+ height: width / 9,
+ },
+ innerContainer: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ width: width / 9,
+ flex: 1,
+ },
+ disabled: {
+ color: '#a9a9a9',
+ },
+});
+
+export class NotificationButton extends Component {
+ static propTypes = {
+ /** @ignore */
+ theme: PropTypes.object.isRequired,
+ /** @ignore */
+ isModalActive: PropTypes.bool.isRequired,
+ /** @ignore */
+ clearLog: PropTypes.func.isRequired,
+ /** @ignore */
+ toggleModalActivity: PropTypes.func.isRequired,
+ /** @ignore */
+ isTransitioning: PropTypes.bool.isRequired,
+ /** @ignore */
+ notificationLog: PropTypes.array.isRequired,
+ /** Determines whether to display topBar when modal is open */
+ displayTopBar: PropTypes.bool,
+ };
+
+ static defaultProps = {
+ displayTopBar: true,
+ };
+
+ /**
+ * Displays error log
+ *
+ * @method showModal
+ */
+ showModal() {
+ const { isTransitioning, theme, notificationLog, displayTopBar } = this.props;
+ if (!isTransitioning) {
+ this.props.toggleModalActivity('notificationLog', {
+ hideModal: this.props.toggleModalActivity,
+ theme,
+ notificationLog,
+ clearLog: this.props.clearLog,
+ displayTopBar,
+ });
+ }
+ }
+
+ render() {
+ const { theme: { bar }, isModalActive, notificationLog } = this.props;
+ const hasNotifications = size(notificationLog) && notificationLog.length > 0;
+
+ return (
+
+ {(hasNotifications && (
+ this.showModal()} style={styles.innerContainer}>
+
+
+ )) || }
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => ({
+ theme: getThemeFromState(state),
+ isModalActive: state.ui.isModalActive,
+ isTransitioning: state.ui.isTransitioning,
+ notificationLog: state.alerts.notificationLog,
+});
+
+const mapDispatchToProps = {
+ clearLog,
+ toggleModalActivity,
+};
+
+export default withNamespaces(['enterSeed', 'global'])(
+ connect(mapStateToProps, mapDispatchToProps)(NotificationButton),
+);
diff --git a/src/mobile/src/ui/components/NotificationLogModal.js b/src/mobile/src/ui/components/NotificationLogModal.js
index 5abcd5acf4..72fee5754a 100644
--- a/src/mobile/src/ui/components/NotificationLogModal.js
+++ b/src/mobile/src/ui/components/NotificationLogModal.js
@@ -52,6 +52,12 @@ export class NotificationLogModal extends PureComponent {
clearLog: PropTypes.func.isRequired,
/** @ignore */
t: PropTypes.func.isRequired,
+ /** Deteremines whether to display the topbar */
+ displayTopBar: PropTypes.bool,
+ };
+
+ static defaultProps = {
+ displayTopBar: true,
};
constructor() {
@@ -84,7 +90,7 @@ export class NotificationLogModal extends PureComponent {
return (
this.clearNotificationLog()}
onRightButtonPress={() => this.props.hideModal()}
diff --git a/src/mobile/src/ui/components/TopBar.js b/src/mobile/src/ui/components/TopBar.js
index 18250088ec..7c6f32b49b 100644
--- a/src/mobile/src/ui/components/TopBar.js
+++ b/src/mobile/src/ui/components/TopBar.js
@@ -8,7 +8,6 @@ import { connect } from 'react-redux';
import { withNamespaces } from 'react-i18next';
import { toggleTopBarDisplay } from 'shared-modules/actions/home';
import { setSeedIndex } from 'shared-modules/actions/wallet';
-import { clearLog } from 'shared-modules/actions/alerts';
import { toggleModalActivity } from 'shared-modules/actions/ui';
import {
getBalanceForSelectedAccount,
@@ -34,6 +33,7 @@ import { accumulateBalance } from 'shared-modules/libs/iota/addresses';
import { Icon } from 'ui/theme/icons';
import { isIPhoneX } from 'libs/device';
import { Styling } from 'ui/theme/general';
+import NotificationButtonComponent from 'ui/components/NotificationButton';
const { height, width } = Dimensions.get('window');
@@ -130,10 +130,6 @@ class TopBar extends Component {
theme: PropTypes.object.isRequired,
/** @ignore */
setPollFor: PropTypes.func.isRequired,
- /** @ignore */
- notificationLog: PropTypes.array.isRequired,
- /** @ignore */
- clearLog: PropTypes.func.isRequired,
/** Top bar height */
topBarHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
/** @ignore */
@@ -277,18 +273,6 @@ class TopBar extends Component {
);
}
- showModal() {
- const { isTransitioning, theme, notificationLog } = this.props;
- if (!isTransitioning) {
- this.props.toggleModalActivity('notificationLog', {
- hideModal: () => this.hideModal(),
- theme,
- notificationLog,
- clearLog: this.props.clearLog,
- });
- }
- }
-
hideModal() {
this.props.toggleModalActivity();
}
@@ -302,7 +286,6 @@ class TopBar extends Component {
seedIndex,
theme: { bar, primary },
isKeyboardActive,
- notificationLog,
mode,
minimised,
currentRoute,
@@ -327,7 +310,6 @@ class TopBar extends Component {
const withSubtitles = (title, index) => ({ title, subtitle: getBalance(index), index });
const titles = map(accountNames, withSubtitles);
const hasMultipleSeeds = size(TopBar.filterSeedTitles(accountNames, seedIndex));
- const hasNotifications = size(notificationLog) && notificationLog.length > 0;
const shouldDisable = this.shouldDisable();
const baseContent = (
@@ -344,22 +326,10 @@ class TopBar extends Component {
{(!isKeyboardActive &&
!minimised && (
-
- {(hasNotifications &&
- !isKeyboardActive &&
- mode === 'Advanced' && (
- this.showModal()}
- style={styles.iconWrapper}
- >
-
-
- )) || }
+
+ {(!isKeyboardActive && mode === 'Advanced' && ) || (
+
+ )}
-
+
{(hasMultipleSeeds && (
({
isTopBarActive: state.home.isTopBarActive,
selectedAccount: selectAccountInfo(state),
theme: getThemeFromState(state),
- notificationLog: state.alerts.notificationLog,
isFetchingLatestAccountInfo: state.ui.isFetchingAccountInfo,
currentRoute: state.home.childRoute,
isKeyboardActive: state.ui.isKeyboardActive,
@@ -557,7 +526,6 @@ const mapDispatchToProps = {
toggleModalActivity,
setSeedIndex,
setPollFor,
- clearLog,
};
export default withNamespaces('global')(connect(mapStateToProps, mapDispatchToProps)(TopBar));
diff --git a/src/mobile/src/ui/routes/entry.js b/src/mobile/src/ui/routes/entry.js
index 797ecd1529..d5aaca435f 100644
--- a/src/mobile/src/ui/routes/entry.js
+++ b/src/mobile/src/ui/routes/entry.js
@@ -95,6 +95,7 @@ const renderInitialScreen = (initialScreen, state) => {
drawBehind: true,
backgroundColor: theme.body.bg,
},
+ popGesture: false,
};
Navigation.setDefaultOptions(options);
@@ -203,7 +204,7 @@ onAppStart()
const { settings: { versions, completedMigration } } = reduxState;
if (
- versions.buildNumber < 42 &&
+ versions.buildNumber < 43 &&
completedMigration === false &&
// Also check if there is persisted data in AsyncStorage that needs to be migrated
// If this check is omitted, the condition will be satisfied on a fresh install.
diff --git a/src/mobile/src/ui/views/wallet/History.js b/src/mobile/src/ui/views/wallet/History.js
index f732fc208d..15d9652afe 100644
--- a/src/mobile/src/ui/views/wallet/History.js
+++ b/src/mobile/src/ui/views/wallet/History.js
@@ -146,6 +146,7 @@ class History extends Component {
newProps.isPromotingTransaction ||
newProps.isRetryingFailedTransaction,
isRetryingFailedTransaction: newProps.isRetryingFailedTransaction,
+ isFailedTransaction: !newBundleProps.broadcasted,
bundleIsBeingPromoted:
newProps.currentlyPromotingBundleHash === modalProps.bundle && !newBundleProps.persistence,
});
diff --git a/src/shared/actions/migrations.js b/src/shared/actions/migrations.js
index aa740136c3..4ba6103355 100644
--- a/src/shared/actions/migrations.js
+++ b/src/shared/actions/migrations.js
@@ -95,6 +95,7 @@ export const migrate = (oldStorageAdapter) => (dispatch) => {
// If there is not data to migrate, just mark migration as complete
onComplete();
} else {
+ dispatch(resetProgress());
dispatch(
generateAlert(
'error',
diff --git a/src/shared/locales/en/translation.json b/src/shared/locales/en/translation.json
index 2cfbba9f60..9dc667a6fc 100644
--- a/src/shared/locales/en/translation.json
+++ b/src/shared/locales/en/translation.json
@@ -781,7 +781,7 @@
},
"migration": {
"dataMigration": "Data migration",
- "dataMigrationExplanation": "Due to performance and storage limitations, Trinity is using a new database for storing settings and account data. Please wait while Trinity automatically migrates your existing data",
+ "dataMigrationExplanation": "Due to performance and storage limitations, Trinity is using a new database for storing settings and account data. Please wait while Trinity automatically migrates your existing data.",
"problemMigratingYourData": "There was a problem migrating your data. Please try again"
},
"ledger": {
@@ -816,4 +816,4 @@
"applicationNotInitialised": "Warning unconfirmed",
"applicationNotInitialisedExplanation": "Reopen the IOTA app on your Ledger device, accept the informational warning and try again."
}
-}
\ No newline at end of file
+}
diff --git a/src/shared/storage/index.js b/src/shared/storage/index.js
index 66cb548480..4f1a1b395d 100644
--- a/src/shared/storage/index.js
+++ b/src/shared/storage/index.js
@@ -170,7 +170,7 @@ class Account {
realm.write(() => {
// Create account with new name.
- realm.create('Account', assign({}, accountData, { accountName: to }));
+ realm.create('Account', assign({}, accountData, { name: to }));
// Delete account with old name.
realm.delete(accountData);
});