diff --git a/apps/mobile/src/components/Dialog/BaseDialog.js b/apps/mobile/src/components/Dialog/BaseDialog.js
index 57aff4d17..f343b5399 100644
--- a/apps/mobile/src/components/Dialog/BaseDialog.js
+++ b/apps/mobile/src/components/Dialog/BaseDialog.js
@@ -18,6 +18,7 @@ const BaseDialog = ({
onShow,
animation = 'fade',
premium,
+ statusBarTranslucent=true
}) => {
const [state, dispatch] = useTracked();
const scaleValue = new Animated.Value(1);
@@ -27,7 +28,7 @@ const BaseDialog = ({
visible={visible}
transparent={true}
animated
- statusBarTranslucent
+ statusBarTranslucent={statusBarTranslucent}
onShow={() => {
if (onShow) {
onShow();
diff --git a/apps/mobile/src/components/Dialog/DialogButtons.js b/apps/mobile/src/components/Dialog/DialogButtons.js
index b0aabc4c9..bed33e061 100644
--- a/apps/mobile/src/components/Dialog/DialogButtons.js
+++ b/apps/mobile/src/components/Dialog/DialogButtons.js
@@ -1,5 +1,6 @@
import React from 'react';
-import {StyleSheet, View} from 'react-native';
+import {ActivityIndicator, StyleSheet, View} from 'react-native';
+import {useTracked} from '../../provider';
import {SIZE} from '../../utils/SizeUtils';
import {Button} from '../Button';
@@ -8,28 +9,40 @@ const DialogButtons = ({
onPressNegative,
positiveTitle,
negativeTitle = 'Cancel',
+ loading,
}) => {
+ const [state] = useTracked();
+ const {colors} = state;
+
return (
-
- {onPressPositive && (
+ {loading ? (
+
+ ) : }
+
+
- )}
+ {onPressPositive && (
+
+ )}
+
);
};
@@ -38,7 +51,7 @@ export default DialogButtons;
const styles = StyleSheet.create({
container: {
- justifyContent: 'flex-end',
+ justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
marginTop: 20,
diff --git a/apps/mobile/src/components/VaultDialog/index.js b/apps/mobile/src/components/VaultDialog/index.js
index edd4459a8..b30639ef8 100644
--- a/apps/mobile/src/components/VaultDialog/index.js
+++ b/apps/mobile/src/components/VaultDialog/index.js
@@ -33,13 +33,14 @@ import Paragraph from '../Typography/Paragraph';
const passInputRef = createRef();
const confirmPassRef = createRef();
-
+const changePassInputRef = createRef();
export class VaultDialog extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
wrongPassword: false,
+ loading: false,
note: {},
vault: false,
locked: true,
@@ -52,9 +53,11 @@ export class VaultDialog extends Component {
biometricUnlock: false,
isBiometryAvailable: false,
fingerprintAccess: false,
+ changePassword: false,
};
this.password = null;
this.confirmPassword = null;
+ this.newPassword = null;
}
componentDidMount() {
@@ -94,6 +97,7 @@ export class VaultDialog extends Component {
isBiometryAvailable: available,
biometricUnlock: fingerprint,
fingerprintAccess: data.fingerprintAccess,
+ changePassword: data.changePassword,
});
if (fingerprint && this.state.novault && !this.state.fingerprintAccess) {
await this._onPressFingerprintAuth();
@@ -101,6 +105,10 @@ export class VaultDialog extends Component {
};
close = () => {
+ if (this.state.loading) {
+ ToastEvent.show('Please wait and do not close the app.', 'success');
+ return;
+ }
updateEvent({type: Actions.NOTES});
this.password = null;
@@ -119,8 +127,9 @@ export class VaultDialog extends Component {
};
onPress = async () => {
+ if (this.state.loading) return;
if (!this.state.novault) {
- if (this.password.length < 3) {
+ if (this.password && this.password.length < 3) {
ToastEvent.show('Password too short', 'error', 'local');
return;
@@ -134,6 +143,35 @@ export class VaultDialog extends Component {
}
this._createVault();
+ } else if (this.state.changePassword) {
+ if (this.newPassword && this.newPassword.length < 3) {
+ ToastEvent.show('New password too short', 'error', 'local');
+ return;
+ }
+ this.setState({
+ loading: true,
+ });
+
+ db.vault
+ .changePassword(this.password, this.newPassword)
+ .then((result) => {
+ this.setState({
+ loading: false,
+ });
+ if (this.state.biometricUnlock) {
+ this._enrollFingerprint(this.newPassword);
+ }
+ ToastEvent.show('Vault password changed', 'success');
+ this.close();
+ })
+ .catch((e) => {
+ this.setState({
+ loading: false,
+ });
+ if (e === db.vault.ERRORS.wrongPassword) {
+ ToastEvent.show('Current password incorrect.', 'error', 'local');
+ }
+ });
} else if (this.state.locked) {
if (!this.password || this.password.trim() === 0) {
ToastEvent.show('Password is invalid', 'error', 'local');
@@ -159,7 +197,7 @@ export class VaultDialog extends Component {
});
}
} else if (this.state.fingerprintEnroll) {
- this._enrollFingerprint();
+ this._enrollFingerprint(this.password);
}
};
@@ -214,20 +252,13 @@ export class VaultDialog extends Component {
ToastEvent.show('Note deleted', 'success', 'local');
}
- async _enrollFingerprint() {
+ async _enrollFingerprint(password) {
try {
- await Keychain.setInternetCredentials(
- 'nn_vault',
- 'nn_vault',
- this.password,
- {
- accessControl:
- Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
- authenticationPrompt: {cancel: null},
- accessible:
- Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS,
- },
- );
+ await Keychain.setInternetCredentials('nn_vault', 'nn_vault', password, {
+ accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
+ authenticationPrompt: {cancel: null},
+ accessible: Keychain.AUTHENTICATION_TYPE.DEVICE_PASSCODE_OR_BIOMETRICS,
+ });
} catch (e) {
this._takeErrorAction(e);
}
@@ -320,6 +351,13 @@ export class VaultDialog extends Component {
locked,
permanant,
biometricUnlock,
+ deleteNote,
+ share,
+ goToEditor,
+ fingerprintAccess,
+ changePassword,
+ copyNote,
+ loading,
} = this.state;
if (!visible) return null;
@@ -328,6 +366,7 @@ export class VaultDialog extends Component {
onShow={() => {
passInputRef.current?.focus();
}}
+ statusBarTranslucent={false}
onRequestClose={this.close}
visible={true}>
+
- {!this.state.biometricUnlock || !novault ? null : (
+ {!this.state.biometricUnlock ||
+ !novault ||
+ changePassword ? null : (
) : null}
+ {changePassword ? (
+ <>
+ {
+ this.newPassword = value;
+ }}
+ onFocus={() => {
+ this.setState({
+ focusIndex: 0,
+ });
+ }}
+ secureTextEntry
+ placeholder={'New Password'}
+ placeholderTextColor={colors.icon}
+ />
+
+ >
+ ) : null}
+
{!novault ? (
{
this.setState({
@@ -540,15 +623,18 @@ export class VaultDialog extends Component {
{
* @typedef {Object} vaultType
* @property {Object} item
* @property {boolean} novault
- * @property {Object} locked
- * @property {Object} permanant
- * @property {Object} goToEditor
- * @property {Object} share
- * @property {Object} deleteNote
- * @property {Object} fingerprintAccess
- * @property {Object} copyNote
+ * @property {boolean} locked
+ * @property {boolean} permanant
+ * @property {boolean} goToEditor
+ * @property {boolean} share
+ * @property {boolean} deleteNote
+ * @property {boolean} fingerprintAccess
+ * @property {boolean} changePassword
+ * @property {boolean} copyNote
* @param {vaultType} data
*/
diff --git a/apps/mobile/src/views/Settings/index.js b/apps/mobile/src/views/Settings/index.js
index 0c9a89d0c..82af3bf92 100644
--- a/apps/mobile/src/views/Settings/index.js
+++ b/apps/mobile/src/views/Settings/index.js
@@ -783,38 +783,52 @@ export const Settings = ({navigation}) => {
/>
{vaultStatus.exists ? (
- vaultStatus.isBiometryAvailable ? (
+ <>
+ {vaultStatus.isBiometryAvailable ? (
+ {
+ openVault({
+ item: {},
+ fingerprintAccess: true,
+ novault: true,
+ });
+ }}
+ maxWidth="90%"
+ customComponent={
+
+ }
+ />
+ ) : null}
{
openVault({
item: {},
- fingerprintAccess: true,
+ changePassword: true,
novault: true,
});
}}
- maxWidth="90%"
- customComponent={
-
- }
/>
- ) : null
+ >
) : (