forked from Ivasoft/mattermost-mobile
Fix Android sharing files without extension (#1646)
This commit is contained in:
@@ -7,6 +7,7 @@ import android.os.Build;
|
|||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ public class RealPathUtil {
|
|||||||
cacheDir.mkdirs();
|
cacheDir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String mimeType = getMimeType(uri.getPath());
|
||||||
tmpFile = File.createTempFile("tmp", fileName, cacheDir);
|
tmpFile = File.createTempFile("tmp", fileName, cacheDir);
|
||||||
|
|
||||||
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
|
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
|
||||||
@@ -182,6 +184,11 @@ public class RealPathUtil {
|
|||||||
return getMimeType(file);
|
return getMimeType(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getMimeTypeFromUri(final Context context, final Uri uri) {
|
||||||
|
ContentResolver cR = context.getContentResolver();
|
||||||
|
return cR.getType(uri);
|
||||||
|
}
|
||||||
|
|
||||||
public static void deleteTempFiles(final File dir) {
|
public static void deleteTempFiles(final File dir) {
|
||||||
try {
|
try {
|
||||||
if (dir.isDirectory()) {
|
if (dir.isDirectory()) {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public class ShareModule extends ReactContextBaseJavaModule {
|
|||||||
map = Arguments.createMap();
|
map = Arguments.createMap();
|
||||||
text = "file://" + filePath;
|
text = "file://" + filePath;
|
||||||
map.putString("value", text);
|
map.putString("value", text);
|
||||||
map.putString("type", RealPathUtil.getMimeType(filePath));
|
map.putString("type", RealPathUtil.getMimeTypeFromUri(currentActivity, uri));
|
||||||
items.pushMap(map);
|
items.pushMap(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
import {Platform} from 'react-native';
|
import {Platform} from 'react-native';
|
||||||
import RNFetchBlob from 'react-native-fetch-blob';
|
import RNFetchBlob from 'react-native-fetch-blob';
|
||||||
|
import mimeDB from 'mime-db';
|
||||||
|
|
||||||
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
|
||||||
|
|
||||||
import {DeviceTypes} from 'app/constants/';
|
import {DeviceTypes} from 'app/constants/';
|
||||||
|
|
||||||
|
const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
|
||||||
const {DOCUMENTS_PATH, IMAGES_PATH, VIDEOS_PATH} = DeviceTypes;
|
const {DOCUMENTS_PATH, IMAGES_PATH, VIDEOS_PATH} = DeviceTypes;
|
||||||
const DEFAULT_SERVER_MAX_FILE_SIZE = 50 * 1024 * 1024;// 50 Mb
|
const DEFAULT_SERVER_MAX_FILE_SIZE = 50 * 1024 * 1024;// 50 Mb
|
||||||
|
|
||||||
@@ -32,6 +34,9 @@ const SUPPORTED_VIDEO_FORMAT = Platform.select({
|
|||||||
android: ['video/3gpp', 'video/x-matroska', 'video/mp4', 'video/webm'],
|
android: ['video/3gpp', 'video/x-matroska', 'video/mp4', 'video/webm'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const types = {};
|
||||||
|
const extensions = {};
|
||||||
|
|
||||||
export function generateId() {
|
export function generateId() {
|
||||||
// Implementation taken from http://stackoverflow.com/a/2117523
|
// Implementation taken from http://stackoverflow.com/a/2117523
|
||||||
let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
||||||
@@ -144,3 +149,69 @@ export const isVideo = (file) => {
|
|||||||
|
|
||||||
return SUPPORTED_VIDEO_FORMAT.includes(mime);
|
return SUPPORTED_VIDEO_FORMAT.includes(mime);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default extension for a MIME type.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @return {boolean|string}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function getExtensionFromMime(type) {
|
||||||
|
if (!Object.keys(extensions).length) {
|
||||||
|
populateMaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type || typeof type !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use media-typer
|
||||||
|
const match = EXTRACT_TYPE_REGEXP.exec(type);
|
||||||
|
|
||||||
|
// get extensions
|
||||||
|
const exts = match && extensions[match[1].toLowerCase()];
|
||||||
|
|
||||||
|
if (!exts || !exts.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the extensions and types maps.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function populateMaps() {
|
||||||
|
// source preference (least -> most)
|
||||||
|
const preference = ['nginx', 'apache', undefined, 'iana']; //eslint-disable-line no-undefined
|
||||||
|
|
||||||
|
Object.keys(mimeDB).forEach((type) => {
|
||||||
|
const mime = mimeDB[type];
|
||||||
|
const exts = mime.extensions;
|
||||||
|
|
||||||
|
if (!exts || !exts.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions[type] = exts;
|
||||||
|
|
||||||
|
for (let i = 0; i < exts.length; i++) {
|
||||||
|
const extension = exts[i];
|
||||||
|
|
||||||
|
if (types[extension]) {
|
||||||
|
const from = preference.indexOf(mimeDB[types[extension]].source);
|
||||||
|
const to = preference.indexOf(mime.source);
|
||||||
|
|
||||||
|
if (types[extension] !== 'application/octet-stream' &&
|
||||||
|
(from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
types[extension] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {NavigationActions} from 'react-navigation';
|
|||||||
import TouchableItem from 'react-navigation/src/views/TouchableItem';
|
import TouchableItem from 'react-navigation/src/views/TouchableItem';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {intlShape} from 'react-intl';
|
import {intlShape} from 'react-intl';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Image,
|
Image,
|
||||||
NativeModules,
|
NativeModules,
|
||||||
@@ -25,6 +26,7 @@ import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_
|
|||||||
|
|
||||||
import PaperPlane from 'app/components/paper_plane';
|
import PaperPlane from 'app/components/paper_plane';
|
||||||
import mattermostManaged from 'app/mattermost_managed';
|
import mattermostManaged from 'app/mattermost_managed';
|
||||||
|
import {getExtensionFromMime} from 'app/utils/file';
|
||||||
import {emptyFunction} from 'app/utils/general';
|
import {emptyFunction} from 'app/utils/general';
|
||||||
import {preventDoubleTap} from 'app/utils/tap';
|
import {preventDoubleTap} from 'app/utils/tap';
|
||||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||||
@@ -278,15 +280,20 @@ export default class ExtensionPost extends PureComponent {
|
|||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
const fullPath = item.value;
|
const fullPath = item.value;
|
||||||
const filename = fullPath.replace(/^.*[\\/]/, '');
|
|
||||||
const extension = filename.split('.').pop();
|
|
||||||
const fileSize = await RNFetchBlob.fs.stat(fullPath);
|
const fileSize = await RNFetchBlob.fs.stat(fullPath);
|
||||||
|
let filename = fullPath.replace(/^.*[\\/]/, '');
|
||||||
|
let extension = filename.split('.').pop();
|
||||||
|
if (extension === filename) {
|
||||||
|
extension = getExtensionFromMime(item.type);
|
||||||
|
filename = `${filename}.${extension}`;
|
||||||
|
}
|
||||||
|
|
||||||
totalSize += fileSize.size;
|
totalSize += fileSize.size;
|
||||||
files.push({
|
files.push({
|
||||||
extension,
|
extension,
|
||||||
filename,
|
filename,
|
||||||
fullPath,
|
fullPath,
|
||||||
mimeType: lookupMimeType(filename.toLowerCase()),
|
mimeType: item.type || lookupMimeType(filename.toLowerCase()),
|
||||||
size: getFormattedFileSize(fileSize),
|
size: getFormattedFileSize(fileSize),
|
||||||
type: item.type,
|
type: item.type,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user