feat: implement preferences pane
This commit is contained in:
@@ -33,44 +33,47 @@ const ACCOUNT_SWITCHER_ENABLED = false;
|
||||
const ACCOUNT_SWITCHER_FEATURE_KEY = 'account_switcher';
|
||||
|
||||
type DockShortcut = {
|
||||
name: string,
|
||||
component: SNComponent,
|
||||
name: string;
|
||||
component: SNComponent;
|
||||
icon: {
|
||||
type: string
|
||||
background_color: string
|
||||
border_color: string
|
||||
}
|
||||
}
|
||||
type: string;
|
||||
background_color: string;
|
||||
border_color: string;
|
||||
};
|
||||
};
|
||||
|
||||
class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
outOfSync: boolean;
|
||||
hasPasscode: boolean;
|
||||
dataUpgradeAvailable: boolean;
|
||||
dockShortcuts: DockShortcut[];
|
||||
hasAccountSwitcher: boolean;
|
||||
showBetaWarning: boolean;
|
||||
showDataUpgrade: boolean;
|
||||
}> {
|
||||
private $rootScope: ng.IRootScopeService
|
||||
private rooms: SNComponent[] = []
|
||||
private themesWithIcons: SNTheme[] = []
|
||||
private showSyncResolution = false
|
||||
private unregisterComponent: any
|
||||
private rootScopeListener1: any
|
||||
private rootScopeListener2: any
|
||||
public arbitraryStatusMessage?: string
|
||||
public user?: any
|
||||
private offline = true
|
||||
public showAccountMenu = false
|
||||
private didCheckForOffline = false
|
||||
private queueExtReload = false
|
||||
private reloadInProgress = false
|
||||
public hasError = false
|
||||
public isRefreshing = false
|
||||
public lastSyncDate?: string
|
||||
public newUpdateAvailable = false
|
||||
public dockShortcuts: DockShortcut[] = []
|
||||
public roomShowState: Partial<Record<string, boolean>> = {}
|
||||
class FooterViewCtrl extends PureViewCtrl<
|
||||
unknown,
|
||||
{
|
||||
outOfSync: boolean;
|
||||
hasPasscode: boolean;
|
||||
dataUpgradeAvailable: boolean;
|
||||
dockShortcuts: DockShortcut[];
|
||||
hasAccountSwitcher: boolean;
|
||||
showBetaWarning: boolean;
|
||||
showDataUpgrade: boolean;
|
||||
}
|
||||
> {
|
||||
private $rootScope: ng.IRootScopeService;
|
||||
private rooms: SNComponent[] = [];
|
||||
private themesWithIcons: SNTheme[] = [];
|
||||
private showSyncResolution = false;
|
||||
private unregisterComponent: any;
|
||||
private rootScopeListener1: any;
|
||||
private rootScopeListener2: any;
|
||||
public arbitraryStatusMessage?: string;
|
||||
public user?: any;
|
||||
private offline = true;
|
||||
public showAccountMenu = false;
|
||||
private didCheckForOffline = false;
|
||||
private queueExtReload = false;
|
||||
private reloadInProgress = false;
|
||||
public hasError = false;
|
||||
public isRefreshing = false;
|
||||
public lastSyncDate?: string;
|
||||
public newUpdateAvailable = false;
|
||||
public dockShortcuts: DockShortcut[] = [];
|
||||
public roomShowState: Partial<Record<string, boolean>> = {};
|
||||
private observerRemovers: Array<() => void> = [];
|
||||
private completedInitialSync = false;
|
||||
private showingDownloadStatus = false;
|
||||
@@ -117,7 +120,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
this.showAccountMenu = this.appState.accountMenu.show;
|
||||
this.setState({
|
||||
showBetaWarning: showBetaWarning,
|
||||
showDataUpgrade: !showBetaWarning
|
||||
showDataUpgrade: !showBetaWarning,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -128,7 +131,9 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
/** Enable permanently for this user so they don't lose the feature after its disabled */
|
||||
localStorage.setItem(ACCOUNT_SWITCHER_FEATURE_KEY, JSON.stringify(true));
|
||||
}
|
||||
const hasAccountSwitcher = stringValue ? JSON.parse(stringValue) : ACCOUNT_SWITCHER_ENABLED;
|
||||
const hasAccountSwitcher = stringValue
|
||||
? JSON.parse(stringValue)
|
||||
: ACCOUNT_SWITCHER_ENABLED;
|
||||
this.setState({ hasAccountSwitcher });
|
||||
}
|
||||
|
||||
@@ -148,7 +153,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
reloadUpgradeStatus() {
|
||||
this.application.checkForSecurityUpdate().then((available) => {
|
||||
this.setState({
|
||||
dataUpgradeAvailable: available
|
||||
dataUpgradeAvailable: available,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -176,19 +181,25 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
async reloadPasscodeStatus() {
|
||||
const hasPasscode = this.application.hasPasscode();
|
||||
this.setState({
|
||||
hasPasscode: hasPasscode
|
||||
hasPasscode: hasPasscode,
|
||||
});
|
||||
}
|
||||
|
||||
addRootScopeListeners() {
|
||||
this.rootScopeListener1 = this.$rootScope.$on(RootScopeMessages.ReloadExtendedData, () => {
|
||||
this.reloadExtendedData();
|
||||
});
|
||||
this.rootScopeListener2 = this.$rootScope.$on(RootScopeMessages.NewUpdateAvailable, () => {
|
||||
this.$timeout(() => {
|
||||
this.onNewUpdateAvailable();
|
||||
});
|
||||
});
|
||||
this.rootScopeListener1 = this.$rootScope.$on(
|
||||
RootScopeMessages.ReloadExtendedData,
|
||||
() => {
|
||||
this.reloadExtendedData();
|
||||
}
|
||||
);
|
||||
this.rootScopeListener2 = this.$rootScope.$on(
|
||||
RootScopeMessages.NewUpdateAvailable,
|
||||
() => {
|
||||
this.$timeout(() => {
|
||||
this.onNewUpdateAvailable();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
@@ -202,11 +213,11 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
}
|
||||
break;
|
||||
case AppStateEvent.BeganBackupDownload:
|
||||
statusService.setMessage("Saving local backup…");
|
||||
statusService.setMessage('Saving local backup…');
|
||||
break;
|
||||
case AppStateEvent.EndedBackupDownload: {
|
||||
const successMessage = "Successfully saved backup.";
|
||||
const errorMessage = "Unable to save local backup.";
|
||||
const successMessage = 'Successfully saved backup.';
|
||||
const errorMessage = 'Unable to save local backup.';
|
||||
statusService.setMessage(data.success ? successMessage : errorMessage);
|
||||
|
||||
const twoSeconds = 2000;
|
||||
@@ -237,12 +248,12 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
break;
|
||||
case ApplicationEvent.EnteredOutOfSync:
|
||||
this.setState({
|
||||
outOfSync: true
|
||||
outOfSync: true,
|
||||
});
|
||||
break;
|
||||
case ApplicationEvent.ExitedOutOfSync:
|
||||
this.setState({
|
||||
outOfSync: false
|
||||
outOfSync: false,
|
||||
});
|
||||
break;
|
||||
case ApplicationEvent.CompletedFullSync:
|
||||
@@ -290,17 +301,15 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
CollectionSort.Title,
|
||||
'asc',
|
||||
(theme: SNTheme) => {
|
||||
return (
|
||||
theme.package_info &&
|
||||
theme.package_info.dock_icon
|
||||
);
|
||||
return theme.package_info && theme.package_info.dock_icon;
|
||||
}
|
||||
);
|
||||
|
||||
this.observerRemovers.push(this.application.streamItems(
|
||||
ContentType.Component,
|
||||
async () => {
|
||||
const components = this.application.getItems(ContentType.Component) as SNComponent[];
|
||||
this.observerRemovers.push(
|
||||
this.application.streamItems(ContentType.Component, async () => {
|
||||
const components = this.application.getItems(
|
||||
ContentType.Component
|
||||
) as SNComponent[];
|
||||
this.rooms = components.filter((candidate) => {
|
||||
return candidate.area === ComponentArea.Rooms && !candidate.deleted;
|
||||
});
|
||||
@@ -308,33 +317,38 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
this.queueExtReload = false;
|
||||
this.reloadExtendedData();
|
||||
}
|
||||
}
|
||||
));
|
||||
})
|
||||
);
|
||||
|
||||
this.observerRemovers.push(this.application.streamItems(
|
||||
ContentType.Theme,
|
||||
async () => {
|
||||
const themes = this.application.getDisplayableItems(ContentType.Theme) as SNTheme[];
|
||||
this.observerRemovers.push(
|
||||
this.application.streamItems(ContentType.Theme, async () => {
|
||||
const themes = this.application.getDisplayableItems(
|
||||
ContentType.Theme
|
||||
) as SNTheme[];
|
||||
this.themesWithIcons = themes;
|
||||
this.reloadDockShortcuts();
|
||||
}
|
||||
));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
registerComponentHandler() {
|
||||
this.unregisterComponent = this.application.componentManager!.registerHandler({
|
||||
identifier: 'room-bar',
|
||||
areas: [ComponentArea.Rooms, ComponentArea.Modal],
|
||||
focusHandler: (component, focused) => {
|
||||
if (component.isEditor() && focused) {
|
||||
if (component.package_info?.identifier === 'org.standardnotes.standard-sheets') {
|
||||
return;
|
||||
this.unregisterComponent =
|
||||
this.application.componentManager!.registerHandler({
|
||||
identifier: 'room-bar',
|
||||
areas: [ComponentArea.Rooms, ComponentArea.Modal],
|
||||
focusHandler: (component, focused) => {
|
||||
if (component.isEditor() && focused) {
|
||||
if (
|
||||
component.package_info?.identifier ===
|
||||
'org.standardnotes.standard-sheets'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.closeAllRooms();
|
||||
this.closeAccountMenu();
|
||||
}
|
||||
this.closeAllRooms();
|
||||
this.closeAccountMenu();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateSyncStatus() {
|
||||
@@ -354,17 +368,17 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
statusManager.setMessage('');
|
||||
}, 2000);
|
||||
} else if (stats.uploadTotalCount > 20) {
|
||||
const completionPercentage = stats.uploadCompletionCount === 0
|
||||
? 0
|
||||
: stats.uploadCompletionCount / stats.uploadTotalCount;
|
||||
const completionPercentage =
|
||||
stats.uploadCompletionCount === 0
|
||||
? 0
|
||||
: stats.uploadCompletionCount / stats.uploadTotalCount;
|
||||
|
||||
const stringPercentage = completionPercentage.toLocaleString(
|
||||
undefined,
|
||||
{ style: 'percent' }
|
||||
);
|
||||
const stringPercentage = completionPercentage.toLocaleString(undefined, {
|
||||
style: 'percent',
|
||||
});
|
||||
|
||||
statusManager.setMessage(
|
||||
`Syncing ${stats.uploadTotalCount} items (${stringPercentage} complete)`,
|
||||
`Syncing ${stats.uploadTotalCount} items (${stringPercentage} complete)`
|
||||
);
|
||||
} else {
|
||||
statusManager.setMessage('');
|
||||
@@ -398,8 +412,10 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
* then closing it after a short delay.
|
||||
*/
|
||||
const extWindow = this.rooms.find((room) => {
|
||||
return room.package_info.identifier === this.application
|
||||
.getNativeExtService().extManagerId;
|
||||
return (
|
||||
room.package_info.identifier ===
|
||||
this.application.getNativeExtService().extManagerId
|
||||
);
|
||||
});
|
||||
if (!extWindow) {
|
||||
this.queueExtReload = true;
|
||||
@@ -419,11 +435,13 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
}
|
||||
|
||||
async openSecurityUpdate() {
|
||||
if (await confirmDialog({
|
||||
title: STRING_UPGRADE_ACCOUNT_CONFIRM_TITLE,
|
||||
text: STRING_UPGRADE_ACCOUNT_CONFIRM_TEXT,
|
||||
confirmButtonText: STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON,
|
||||
})) {
|
||||
if (
|
||||
await confirmDialog({
|
||||
title: STRING_UPGRADE_ACCOUNT_CONFIRM_TITLE,
|
||||
text: STRING_UPGRADE_ACCOUNT_CONFIRM_TEXT,
|
||||
confirmButtonText: STRING_UPGRADE_ACCOUNT_CONFIRM_BUTTON,
|
||||
})
|
||||
) {
|
||||
preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_UPGRADE, async () => {
|
||||
await this.application.upgradeProtocolVersion();
|
||||
});
|
||||
@@ -453,25 +471,27 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
|
||||
refreshData() {
|
||||
this.isRefreshing = true;
|
||||
this.application.sync({
|
||||
queueStrategy: SyncQueueStrategy.ForceSpawnNew,
|
||||
checkIntegrity: true
|
||||
}).then((response) => {
|
||||
this.$timeout(() => {
|
||||
this.isRefreshing = false;
|
||||
}, 200);
|
||||
if (response && response.error) {
|
||||
this.application.alertService!.alert(
|
||||
STRING_GENERIC_SYNC_ERROR
|
||||
);
|
||||
} else {
|
||||
this.syncUpdated();
|
||||
}
|
||||
});
|
||||
this.application
|
||||
.sync({
|
||||
queueStrategy: SyncQueueStrategy.ForceSpawnNew,
|
||||
checkIntegrity: true,
|
||||
})
|
||||
.then((response) => {
|
||||
this.$timeout(() => {
|
||||
this.isRefreshing = false;
|
||||
}, 200);
|
||||
if (response && response.error) {
|
||||
this.application.alertService!.alert(STRING_GENERIC_SYNC_ERROR);
|
||||
} else {
|
||||
this.syncUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
syncUpdated() {
|
||||
this.lastSyncDate = dateToLocalizedString(this.application.getLastSyncDate()!);
|
||||
this.lastSyncDate = dateToLocalizedString(
|
||||
this.application.getLastSyncDate()!
|
||||
);
|
||||
}
|
||||
|
||||
onNewUpdateAvailable() {
|
||||
@@ -480,9 +500,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
|
||||
clickedNewUpdateAnnouncement() {
|
||||
this.newUpdateAvailable = false;
|
||||
this.application.alertService!.alert(
|
||||
STRING_NEW_UPDATE_READY
|
||||
);
|
||||
this.application.alertService!.alert(STRING_NEW_UPDATE_READY);
|
||||
}
|
||||
|
||||
reloadDockShortcuts() {
|
||||
@@ -499,7 +517,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
shortcuts.push({
|
||||
name: name,
|
||||
component: theme,
|
||||
icon: icon
|
||||
icon: icon,
|
||||
} as DockShortcut);
|
||||
}
|
||||
this.setState({
|
||||
@@ -514,7 +532,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
} else {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
})
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -553,7 +571,7 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
text:
|
||||
'If you wish to go back to a stable version, make sure to sign out ' +
|
||||
'of this beta app first.<br>You can silence this warning from the ' +
|
||||
'<em>Account</em> menu.'
|
||||
'<em>Account</em> menu.',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -563,6 +581,10 @@ class FooterViewCtrl extends PureViewCtrl<unknown, {
|
||||
}
|
||||
this.appState.accountMenu.setShow(false);
|
||||
}
|
||||
|
||||
clickPreferences() {
|
||||
this.appState.preferences.openPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
export class FooterView extends WebDirective {
|
||||
@@ -575,7 +597,7 @@ export class FooterView extends WebDirective {
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
application: '=',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user