From e13669af5615526fecf78d53698916056c888087 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 30 Dec 2022 10:44:30 +0100 Subject: [PATCH] Support migrating from older database --- src/utils/storage/migrations/legacy/app.ts | 4 + .../storage/migrations/legacy/contexts.ts | 19 ++++ .../storage/migrations/legacy/instance.ts | 67 ++++++++++++++ .../storage/migrations/legacy/settings.ts | 8 ++ src/utils/storage/migrations/toMMKV.ts | 88 ++++++++++++++++--- 5 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 src/utils/storage/migrations/legacy/app.ts create mode 100644 src/utils/storage/migrations/legacy/contexts.ts create mode 100644 src/utils/storage/migrations/legacy/instance.ts create mode 100644 src/utils/storage/migrations/legacy/settings.ts diff --git a/src/utils/storage/migrations/legacy/app.ts b/src/utils/storage/migrations/legacy/app.ts new file mode 100644 index 00000000..314d6855 --- /dev/null +++ b/src/utils/storage/migrations/legacy/app.ts @@ -0,0 +1,4 @@ +export type LegacyApp = { + expoToken?: string + versionUpdate: boolean +} diff --git a/src/utils/storage/migrations/legacy/contexts.ts b/src/utils/storage/migrations/legacy/contexts.ts new file mode 100644 index 00000000..28306a7d --- /dev/null +++ b/src/utils/storage/migrations/legacy/contexts.ts @@ -0,0 +1,19 @@ +import { ScreenTabsStackParamList } from '@utils/navigation/navigators' + +export type LegacyContexts = { + storeReview: { + context: Readonly + current: number + shown: boolean + } + publicRemoteNotice: { + context: Readonly + current: number + hidden: boolean + } + previousTab: Extract< + keyof ScreenTabsStackParamList, + 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me' + > + previousSegment?: Extract +} diff --git a/src/utils/storage/migrations/legacy/instance.ts b/src/utils/storage/migrations/legacy/instance.ts new file mode 100644 index 00000000..580a25e8 --- /dev/null +++ b/src/utils/storage/migrations/legacy/instance.ts @@ -0,0 +1,67 @@ +import { ComposeStateDraft } from '@screens/Compose/utils/types' + +export type LegacyInstance = { + active: boolean + appData: { + clientId: string + clientSecret: string + } + url: string + token: string + uri: Mastodon.Instance<'v1'>['uri'] + urls: Mastodon.Instance<'v1'>['urls'] + account: { + id: Mastodon.Account['id'] + acct: Mastodon.Account['acct'] + avatarStatic: Mastodon.Account['avatar_static'] + preferences?: Mastodon.Preferences + } + version: string + configuration?: Mastodon.Instance['configuration'] + filters: Mastodon.Filter[] + notifications_filter: { + follow: boolean + follow_request: boolean + favourite: boolean + reblog: boolean + mention: boolean + poll: boolean + status: boolean + update: boolean + 'admin.sign_up'?: boolean + 'admin.report'?: boolean + } + push: { + global: { value: boolean } | boolean + decode: { value: boolean } | boolean + alerts: { + follow: { value: boolean } | boolean + follow_request: { value: boolean } | boolean + favourite: { value: boolean } | boolean + reblog: { value: boolean } | boolean + mention: { value: boolean } | boolean + poll: { value: boolean } | boolean + status?: { value: boolean } | boolean + update?: { value: boolean } | boolean + 'admin.sign_up': { value: boolean } | boolean + 'admin.report': { value: boolean } | boolean + } + keys: { auth?: string } + } + followingPage?: { + showBoosts: boolean + showReplies: boolean + } + mePage: { + followedTags?: { shown: boolean } + lists: { shown: boolean } + announcements: { shown: boolean; unread: number } + } + drafts: ComposeStateDraft[] + frequentEmojis: { + emoji: Pick + score: number + count: number + lastUsed: number + }[] +} diff --git a/src/utils/storage/migrations/legacy/settings.ts b/src/utils/storage/migrations/legacy/settings.ts new file mode 100644 index 00000000..94f342ed --- /dev/null +++ b/src/utils/storage/migrations/legacy/settings.ts @@ -0,0 +1,8 @@ +export type LegacySettings = { + fontsize: -1 | 0 | 1 | 2 | 3 | string + language: string + theme: 'light' | 'dark' | 'auto' + darkTheme: 'lighter' | 'darker' + browser: 'internal' | 'external' + staticEmoji: boolean +} diff --git a/src/utils/storage/migrations/toMMKV.ts b/src/utils/storage/migrations/toMMKV.ts index 1284c2fa..3b053d20 100644 --- a/src/utils/storage/migrations/toMMKV.ts +++ b/src/utils/storage/migrations/toMMKV.ts @@ -2,6 +2,10 @@ import AsyncStorage from '@react-native-async-storage/async-storage' import log from '@utils/startup/log' import { secureStorage, storage } from '@utils/storage' import { MMKV } from 'react-native-mmkv' +import { LegacyApp } from './legacy/app' +import { LegacyContexts } from './legacy/contexts' +import { LegacyInstance } from './legacy/instance' +import { LegacySettings } from './legacy/settings' export const versionStorageGlobal = storage.global.getNumber('version.global') @@ -9,6 +13,9 @@ export async function migrateFromAsyncStorage(): Promise { log('log', 'Migration', 'Migrating...') const start = global.performance.now() + const unwrapPushData = (setting: { value: boolean } | boolean | undefined): boolean => + typeof setting === 'object' ? setting.value : typeof setting === 'boolean' ? setting : true + const keys = ['persist:app', 'persist:contexts', 'persist:settings'] as [ 'persist:app', 'persist:contexts', @@ -21,13 +28,13 @@ export async function migrateFromAsyncStorage(): Promise { if (value != null) { switch (key) { case 'persist:app': - const storeApp = JSON.parse(value) + const storeApp: LegacyApp = JSON.parse(value) if (storeApp.expoToken?.length) { storage.global.set('app.expo_token', storeApp.expoToken.replaceAll(`\"`, ``)) } break case 'persist:contexts': - const storeContexts = JSON.parse(value) + const storeContexts: LegacyContexts = JSON.parse(value) if (storeContexts.storeReview.current) { storage.global.set( 'app.count_till_store_review', @@ -37,17 +44,22 @@ export async function migrateFromAsyncStorage(): Promise { storage.global.set('app.prev_tab', storeContexts.previousTab.replaceAll(`\"`, ``)) storage.global.set( 'app.prev_public_segment', - storeContexts.previousSegment.replaceAll(`\"`, ``) + (storeContexts.previousSegment || 'Local').replaceAll(`\"`, ``) ) break case 'persist:settings': - const storeSettings = JSON.parse(value) - storage.global.set('app.font_size', storeSettings.fontsize || 0) + const storeSettings: LegacySettings = JSON.parse(value) + storage.global.set( + 'app.font_size', + (typeof storeSettings.fontsize === 'string' + ? storeSettings.fontsize.replaceAll(`\"`, ``) + : storeSettings.fontsize) || 0 + ) storage.global.set('app.language', storeSettings.language.replaceAll(`\"`, ``)) storage.global.set('app.theme', storeSettings.theme.replaceAll(`\"`, ``)) storage.global.set('app.theme.dark', storeSettings.darkTheme.replaceAll(`\"`, ``)) storage.global.set('app.browser', storeSettings.browser.replaceAll(`\"`, ``)) - storage.global.set('app.auto_play_gifv', storeSettings.autoplayGifv || true) + storage.global.set('app.auto_play_gifv', true) break } @@ -66,7 +78,8 @@ export async function migrateFromAsyncStorage(): Promise { const storeInstances: { instances: string } = JSON.parse(value) const accounts: string[] = [] - for (const instance of JSON.parse(storeInstances.instances)) { + let instance: LegacyInstance + for (instance of JSON.parse(storeInstances.instances)) { const account = `${instance.url}/${instance.account.id}` const temp = new MMKV({ id: account }) @@ -83,10 +96,63 @@ export async function migrateFromAsyncStorage(): Promise { if (instance.account.preferences) { temp.set('preferences', JSON.stringify(instance.account.preferences)) } - temp.set('notifications', JSON.stringify(instance.notifications_filter)) - temp.set('push', JSON.stringify(instance.push)) - temp.set('page_local', JSON.stringify(instance.followingPage)) - temp.set('page_me', JSON.stringify(instance.mePage)) + temp.set( + 'notifications', + JSON.stringify({ + ...instance.notifications_filter, + status: + typeof instance.notifications_filter.status === 'boolean' + ? instance.notifications_filter.status + : true, + update: + typeof instance.notifications_filter.update === 'boolean' + ? instance.notifications_filter.update + : true, + 'admin.sign_up': + typeof instance.notifications_filter['admin.sign_up'] === 'boolean' + ? instance.notifications_filter['admin.sign_up'] + : true, + 'admin.report': + typeof instance.notifications_filter['admin.report'] === 'boolean' + ? instance.notifications_filter['admin.report'] + : true + }) + ) + temp.set( + 'push', + JSON.stringify({ + global: unwrapPushData(instance.push.global), + decode: unwrapPushData(instance.push.decode), + alerts: { + follow: unwrapPushData(instance.push.alerts.follow), + follow_request: unwrapPushData(instance.push.alerts.follow_request), + favourite: unwrapPushData(instance.push.alerts.favourite), + reblog: unwrapPushData(instance.push.alerts.reblog), + mention: unwrapPushData(instance.push.alerts.mention), + poll: unwrapPushData(instance.push.alerts.poll), + status: unwrapPushData(instance.push.alerts.status), + update: unwrapPushData(instance.push.alerts.update), + 'admin.sign_up': unwrapPushData(instance.push.alerts['admin.sign_up']), + 'admin.report': unwrapPushData(instance.push.alerts['admin.report']) + } + }) + ) + temp.set( + 'page_local', + JSON.stringify( + instance.followingPage || { + showBoosts: true, + showReplies: true + } + ) + ) + temp.set( + 'page_me', + JSON.stringify({ + ...instance.mePage, + followedTags: instance.mePage.followedTags || { shown: false } + }) + ) temp.set('drafts', JSON.stringify(instance.drafts)) temp.set('emojis_frequent', JSON.stringify(instance.frequentEmojis)) temp.set('version', instance.version)