forked from Ivasoft/mattermost-mobile
[Gekidou] upgrade to RN 68 (old arch) (#6138)
* upgrade to RN 68 (old arch) * remove test setup unused & commented mock * Android target set to 30 * Fix theme when opening app from push notification * upgrade common mark
This commit is contained in:
@@ -15,9 +15,11 @@ import {prepareCommonSystemValues, PrepareCommonSystemValuesArgs, getCommonSyste
|
||||
import {addChannelToTeamHistory, addTeamToTeamHistory, getTeamById, queryMyTeams, removeChannelFromTeamHistory} from '@queries/servers/team';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {dismissAllModalsAndPopToRoot, dismissAllModalsAndPopToScreen} from '@screens/navigation';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {makeCategoryChannelId, makeCategoryId} from '@utils/categories';
|
||||
import {isDMorGM} from '@utils/channel';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {setThemeDefaults, updateThemeIfNeeded} from '@utils/theme';
|
||||
import {displayGroupMessageName, displayUsername, getUserIdFromChannelName} from '@utils/user';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
@@ -84,6 +86,18 @@ export const switchToChannel = async (serverUrl: string, channelId: string, team
|
||||
await operator.batchRecords(models);
|
||||
}
|
||||
|
||||
if (!EphemeralStore.theme) {
|
||||
// When opening the app from a push notification the theme may not be set in the EphemeralStore
|
||||
// causing the goToScreen to use the Appearance theme instead and that causes the screen background color to potentially
|
||||
// not match the theme
|
||||
const themes = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_THEME, toTeamId).fetch();
|
||||
let theme = Preferences.THEMES.denim;
|
||||
if (themes.length) {
|
||||
theme = setThemeDefaults(JSON.parse(themes[0].value) as Theme);
|
||||
}
|
||||
updateThemeIfNeeded(theme, true);
|
||||
}
|
||||
|
||||
if (isTabletDevice) {
|
||||
dismissAllModalsAndPopToRoot();
|
||||
DeviceEventEmitter.emit(NavigationConstants.NAVIGATION_HOME);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Platform, StatusBar, StatusBarStyle, StyleSheet, TouchableOpacity, View} from 'react-native';
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
import FileSystem from 'react-native-fs';
|
||||
import tinyColor from 'tinycolor2';
|
||||
|
||||
import ProgressBar from '@components/progress_bar';
|
||||
@@ -15,6 +15,7 @@ import {useServerUrl} from '@context/server';
|
||||
import NetworkManager from '@init/network_manager';
|
||||
import {alertDownloadDocumentDisabled, alertDownloadFailed, alertFailedToOpenDocument} from '@utils/document';
|
||||
import {fileExists, getLocalFilePathFromFile} from '@utils/file';
|
||||
import {emptyFunction} from '@utils/general';
|
||||
|
||||
import FileIcon from './file_icon';
|
||||
|
||||
@@ -83,7 +84,7 @@ const DocumentFile = forwardRef<DocumentFileRef, DocumentFileProps>(({background
|
||||
}
|
||||
} catch (error) {
|
||||
if (path) {
|
||||
FileSystem.deleteAsync(path, {idempotent: true});
|
||||
FileSystem.unlink(path).catch(emptyFunction);
|
||||
}
|
||||
setDownloading(false);
|
||||
setProgress(0);
|
||||
@@ -136,7 +137,7 @@ const DocumentFile = forwardRef<DocumentFileRef, DocumentFileProps>(({background
|
||||
onDonePreviewingFile();
|
||||
|
||||
if (path) {
|
||||
FileSystem.deleteAsync(path, {idempotent: true});
|
||||
FileSystem.unlink(path).catch(emptyFunction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getThumbnailAsync} from 'expo-video-thumbnails';
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
||||
import {StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||
import {createThumbnail} from 'react-native-create-thumbnail';
|
||||
|
||||
import {updateLocalFile} from '@actions/local/file';
|
||||
import {buildFilePreviewUrl, fetchPublicLink} from '@actions/remote/file';
|
||||
@@ -89,7 +89,7 @@ const VideoFile = ({
|
||||
// library
|
||||
const publicUri = await fetchPublicLink(serverUrl, data.id!);
|
||||
if (('link') in publicUri) {
|
||||
const {uri, height, width} = await getThumbnailAsync(data.localPath || publicUri.link, {time: 2000});
|
||||
const {path: uri, height, width} = await createThumbnail({url: data.localPath || publicUri.link, timeStamp: 2000});
|
||||
data.mini_preview = uri;
|
||||
data.height = height;
|
||||
data.width = width;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import FileSystem from 'react-native-fs';
|
||||
|
||||
export default {
|
||||
DOCUMENTS_PATH: `${FileSystem.cacheDirectory}/Documents`,
|
||||
DOCUMENTS_PATH: `${FileSystem.CachesDirectoryPath}/Documents`,
|
||||
IS_TABLET: DeviceInfo.isTablet(),
|
||||
PUSH_NOTIFY_ANDROID_REACT_NATIVE: 'android_rn',
|
||||
PUSH_NOTIFY_APPLE_REACT_NATIVE: 'apple_rn',
|
||||
|
||||
@@ -8,8 +8,7 @@ import {Appearance, EventSubscription} from 'react-native';
|
||||
import {Preferences} from '@constants';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeCurrentTeamId} from '@queries/servers/system';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {setNavigationStackStyles, setThemeDefaults} from '@utils/theme';
|
||||
import {setThemeDefaults, updateThemeIfNeeded} from '@utils/theme';
|
||||
|
||||
import type {PreferenceModel} from '@database/models/server';
|
||||
import type Database from '@nozbe/watermelondb/Database';
|
||||
@@ -34,15 +33,6 @@ export function getDefaultThemeByAppearance(): Theme {
|
||||
export const ThemeContext = createContext(getDefaultThemeByAppearance());
|
||||
const {Consumer, Provider} = ThemeContext;
|
||||
|
||||
const updateThemeIfNeeded = (theme: Theme) => {
|
||||
if (theme !== EphemeralStore.theme) {
|
||||
EphemeralStore.theme = theme;
|
||||
requestAnimationFrame(() => {
|
||||
setNavigationStackStyles(theme);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const ThemeProvider = ({currentTeamId, children, themes}: Props) => {
|
||||
const getTheme = (): Theme => {
|
||||
if (currentTeamId) {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
import LokiJSAdapter from '@nozbe/watermelondb/adapters/lokijs';
|
||||
import logger from '@nozbe/watermelondb/utils/common/logger';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import {DeviceEventEmitter, Platform} from 'react-native';
|
||||
import FileSystem from 'react-native-fs';
|
||||
|
||||
import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
||||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
@@ -301,8 +301,17 @@ class DatabaseManager {
|
||||
const databaseFile = `${androidFilesDir}${databaseName}.db`;
|
||||
const databaseJournal = `${androidFilesDir}${databaseName}.db-journal`;
|
||||
|
||||
await FileSystem.deleteAsync(databaseFile);
|
||||
await FileSystem.deleteAsync(databaseJournal);
|
||||
try {
|
||||
await FileSystem.unlink(databaseFile);
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
try {
|
||||
await FileSystem.unlink(databaseJournal);
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
factoryReset = async (shouldRemoveDirectory: boolean): Promise<boolean> => {
|
||||
@@ -315,7 +324,7 @@ class DatabaseManager {
|
||||
|
||||
// On Android, we'll remove the databases folder under the Document Directory
|
||||
const androidFilesDir = `${this.databaseDirectory}databases/`;
|
||||
await FileSystem.deleteAsync(androidFilesDir);
|
||||
await FileSystem.unlink(androidFilesDir);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';
|
||||
import logger from '@nozbe/watermelondb/utils/common/logger';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import {DeviceEventEmitter, Platform} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import FileSystem from 'react-native-fs';
|
||||
|
||||
import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
||||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
@@ -24,6 +24,7 @@ import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {queryActiveServer, queryServer, queryServerByIdentifier} from '@queries/app/servers';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import {emptyFunction} from '@utils/general';
|
||||
import {deleteIOSDatabase, getIOSAppGroupDetails} from '@utils/mattermost_managed';
|
||||
import {hashCode} from '@utils/security';
|
||||
|
||||
@@ -49,7 +50,7 @@ class DatabaseManager {
|
||||
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, UserModel,
|
||||
];
|
||||
|
||||
this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : `${FileSystem.documentDirectory}databases/`;
|
||||
this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : `${FileSystem.DocumentDirectoryPath}/databases/`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +83,7 @@ class DatabaseManager {
|
||||
const databaseName = APP_DATABASE;
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
await FileSystem.makeDirectoryAsync(this.databaseDirectory!, {intermediates: true});
|
||||
await FileSystem.mkdir(this.databaseDirectory!);
|
||||
}
|
||||
const databaseFilePath = this.getDatabaseFilePath(databaseName);
|
||||
const modelClasses = this.appModels;
|
||||
@@ -390,9 +391,9 @@ class DatabaseManager {
|
||||
const databaseShm = `${androidFilesDir}${databaseName}.db-shm`;
|
||||
const databaseWal = `${androidFilesDir}${databaseName}.db-wal`;
|
||||
|
||||
FileSystem.deleteAsync(databaseFile, {idempotent: true});
|
||||
FileSystem.deleteAsync(databaseShm, {idempotent: true});
|
||||
FileSystem.deleteAsync(databaseWal, {idempotent: true});
|
||||
FileSystem.unlink(databaseFile).catch(emptyFunction);
|
||||
FileSystem.unlink(databaseShm).catch(emptyFunction);
|
||||
FileSystem.unlink(databaseWal).catch(emptyFunction);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -410,7 +411,7 @@ class DatabaseManager {
|
||||
|
||||
// On Android, we'll remove the databases folder under the Document Directory
|
||||
const androidFilesDir = `${this.databaseDirectory}databases/`;
|
||||
await FileSystem.deleteAsync(androidFilesDir);
|
||||
await FileSystem.unlink(androidFilesDir);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@@ -458,7 +459,7 @@ class DatabaseManager {
|
||||
* @returns {string}
|
||||
*/
|
||||
private getDatabaseFilePath = (dbName: string): string => {
|
||||
return Platform.OS === 'ios' ? `${this.databaseDirectory}/${dbName}.db` : `${this.databaseDirectory}${dbName}.db`;
|
||||
return Platform.OS === 'ios' ? `${this.databaseDirectory}/${dbName}.db` : `${this.databaseDirectory}/${dbName}.db`;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import CameraRoll from '@react-native-community/cameraroll';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {NativeModules, Platform, StyleSheet, Text, View} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
import FileSystem from 'react-native-fs';
|
||||
import {TouchableOpacity} from 'react-native-gesture-handler';
|
||||
import {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
import Share from 'react-native-share';
|
||||
@@ -116,11 +116,10 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction}: Props)
|
||||
|
||||
const cancel = async () => {
|
||||
try {
|
||||
await downloadPromise.current?.cancel?.();
|
||||
downloadPromise.current?.cancel?.();
|
||||
const path = getLocalFilePathFromFile(serverUrl, galleryItemToFileInfo(item));
|
||||
await FileSystem.deleteAsync(path, {idempotent: true});
|
||||
|
||||
downloadPromise.current = undefined;
|
||||
await FileSystem.unlink(path);
|
||||
} catch {
|
||||
// do nothing
|
||||
} finally {
|
||||
@@ -159,7 +158,7 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction}: Props)
|
||||
if (mounted.current) {
|
||||
if (Platform.OS === 'android') {
|
||||
try {
|
||||
await NativeModules.MattermostManaged.saveFile(path.replace('file://', '/'));
|
||||
await NativeModules.MattermostManaged.saveFile(path);
|
||||
} catch {
|
||||
// do nothing in case the user decides not to save the file
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
import {PastedFile} from '@mattermost/react-native-paste-input';
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import mimeDB from 'mime-db';
|
||||
import {IntlShape} from 'react-intl';
|
||||
import {Alert, Platform} from 'react-native';
|
||||
import AndroidOpenSettings from 'react-native-android-open-settings';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {DocumentPickerResponse} from 'react-native-document-picker';
|
||||
import FileSystem from 'react-native-fs';
|
||||
import {Asset} from 'react-native-image-picker';
|
||||
import Permissions, {PERMISSIONS} from 'react-native-permissions';
|
||||
|
||||
@@ -95,61 +95,22 @@ function populateMaps() {
|
||||
});
|
||||
}
|
||||
|
||||
const vectorIconsDir = 'vectorIcons';
|
||||
const dirsToExclude = ['Cache.db', 'WebKit', 'WebView', vectorIconsDir];
|
||||
async function getDirectorySize(fileStats: FileSystem.FileInfo) {
|
||||
if (fileStats?.exists) {
|
||||
let total = 0;
|
||||
if (fileStats.isDirectory) {
|
||||
const exclude = dirsToExclude.find((f) => fileStats.uri.includes(f));
|
||||
if (!exclude) {
|
||||
const paths = await FileSystem.readDirectoryAsync(fileStats.uri);
|
||||
for await (const path of paths) {
|
||||
const info = await FileSystem.getInfoAsync(`${fileStats.uri}/${path}`, {size: true});
|
||||
if (info.isDirectory) {
|
||||
const dirSize = await getDirectorySize(info);
|
||||
total += dirSize;
|
||||
} else {
|
||||
total += (info.size || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
total = fileStats.size;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export async function getFileCacheSize() {
|
||||
if (FileSystem.cacheDirectory) {
|
||||
const cacheStats = await FileSystem.getInfoAsync(FileSystem.cacheDirectory);
|
||||
const size = await getDirectorySize(cacheStats);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export async function deleteV1Data() {
|
||||
const dir = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupSharedDirectory : FileSystem.documentDirectory;
|
||||
const dir = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupSharedDirectory : FileSystem.DocumentDirectoryPath;
|
||||
|
||||
try {
|
||||
const mmkvDirInfo = await FileSystem.getInfoAsync(`${dir}/mmkv`);
|
||||
if (mmkvDirInfo.exists) {
|
||||
await FileSystem.deleteAsync(mmkvDirInfo.uri, {idempotent: true});
|
||||
const directory = `${dir}/mmkv`;
|
||||
const mmkvDirInfo = await FileSystem.exists(directory);
|
||||
if (mmkvDirInfo) {
|
||||
await FileSystem.unlink(directory);
|
||||
}
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
try {
|
||||
const entitiesInfo = await FileSystem.getInfoAsync(`${dir}/entities`);
|
||||
if (entitiesInfo.exists) {
|
||||
const entitiesInfo = await FileSystem.exists(`${dir}/entities`);
|
||||
if (entitiesInfo) {
|
||||
deleteEntititesFile();
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -159,17 +120,17 @@ export async function deleteV1Data() {
|
||||
|
||||
export async function deleteFileCache(serverUrl: string) {
|
||||
const serverDir = hashCode(serverUrl);
|
||||
const cacheDir = `${FileSystem.cacheDirectory}/${serverDir}`;
|
||||
const cacheDir = `${FileSystem.CachesDirectoryPath}/${serverDir}`;
|
||||
if (cacheDir) {
|
||||
const cacheDirInfo = await FileSystem.getInfoAsync(cacheDir);
|
||||
if (cacheDirInfo.exists) {
|
||||
const cacheDirInfo = await FileSystem.exists(cacheDir);
|
||||
if (cacheDirInfo) {
|
||||
if (Platform.OS === 'ios') {
|
||||
await FileSystem.deleteAsync(cacheDir, {idempotent: true});
|
||||
await FileSystem.makeDirectoryAsync(cacheDir, {intermediates: true});
|
||||
await FileSystem.unlink(cacheDir);
|
||||
await FileSystem.mkdir(cacheDir);
|
||||
} else {
|
||||
const lstat = await FileSystem.readDirectoryAsync(cacheDir);
|
||||
lstat.forEach((stat: string) => {
|
||||
FileSystem.deleteAsync(stat, {idempotent: true});
|
||||
const lstat = await FileSystem.readDir(cacheDir);
|
||||
lstat.forEach((stat: FileSystem.ReadDirItem) => {
|
||||
FileSystem.unlink(stat.path);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -363,9 +324,9 @@ export function getLocalFilePathFromFile(serverUrl: string, file: FileInfo | Fil
|
||||
}
|
||||
}
|
||||
|
||||
return `${FileSystem.cacheDirectory}${server}/${filename}-${hashCode(file.id!)}.${extension}`;
|
||||
return `${FileSystem.CachesDirectoryPath}/${server}/${filename}-${hashCode(file.id!)}.${extension}`;
|
||||
} else if (file?.id && file?.extension) {
|
||||
return `${FileSystem.cacheDirectory}${server}/${file.id}.${file.extension}`;
|
||||
return `${FileSystem.CachesDirectoryPath}/${server}/${file.id}.${file.extension}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,10 +358,9 @@ export async function extractFileInfo(files: Array<Asset | DocumentPickerRespons
|
||||
});
|
||||
let fileInfo;
|
||||
try {
|
||||
fileInfo = await FileSystem.getInfoAsync(path);
|
||||
const uri = fileInfo.uri;
|
||||
fileInfo = await FileSystem.stat(path);
|
||||
outFile.size = fileInfo.size || 0;
|
||||
outFile.name = uri.substring(uri.lastIndexOf('/') + 1);
|
||||
outFile.name = path.substring(path.lastIndexOf('/') + 1);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
@@ -446,8 +406,7 @@ export function uploadDisabledWarning(intl: IntlShape) {
|
||||
export const fileExists = async (path: string) => {
|
||||
try {
|
||||
const filePath = Platform.select({ios: path.replace('file://', ''), default: path});
|
||||
const info = await FileSystem.getInfoAsync(filePath);
|
||||
return info.exists;
|
||||
return FileSystem.exists(filePath);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -256,3 +256,12 @@ export function setThemeDefaults(theme: Theme): Theme {
|
||||
|
||||
return processedTheme as Theme;
|
||||
}
|
||||
|
||||
export const updateThemeIfNeeded = (theme: Theme, force = false) => {
|
||||
if (theme !== EphemeralStore.theme || force) {
|
||||
EphemeralStore.theme = theme;
|
||||
requestAnimationFrame(() => {
|
||||
setNavigationStackStyles(theme);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user