Compare commits

...

18 Commits

Author SHA1 Message Date
Djorkaeff Alexandre 8142851fde [REGRESSION] Jitsi Call doesn't send message link (#2277) 2020-07-10 10:58:30 -03:00
Diego Mello 0ecfe0f780 [FIX] getSettings not catching errors (#2271) 2020-07-09 10:34:12 -03:00
Djorkaeff Alexandre b9a3828781 [FIX] Create discussion not working from MessageActions (#2265) 2020-07-08 17:57:28 -03:00
Diego Mello fd3f0a3417 [FIX] Notification preferences update crashing the app (#2262) 2020-07-08 17:54:39 -03:00
Diego Mello fa2c93fa2b [FIX] Mime type check crashing the app (#2264) 2020-07-08 17:54:34 -03:00
Diego Mello 118b1352c4 [FIX] Action sheet cutting emojis on the header (#2263)
* [FIX] Action sheet cutting emojis on the header

* fix tablet case

Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
2020-07-08 17:54:26 -03:00
Diego Mello 3d987cc988 [FIX] Navigation object undefined when tapping sidebar's user header on tablet (#2259) 2020-07-08 17:54:18 -03:00
Diego Mello 766dd8f5e4 [FIX] Android stack animation throwing illegal node ID (#2260) 2020-07-08 17:54:11 -03:00
Djorkaeff Alexandre be718db8a5 [FIX] ImageViewer not recognising gestures after zoomed (#2261)
* [FIX] Zoomed in images must react to gestures

* AnimatedFastImage -> AnimatedImage

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:50 -03:00
Djorkaeff Alexandre 3be67f5a4f [FIX] Get active route returning undefined (#2257)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:45 -03:00
Djorkaeff Alexandre 77917f66f0 [FIX] Register crashing when error data is undefined (#2256)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:39 -03:00
Djorkaeff Alexandre 7d2f4afaae [FIX] ThreadMessagesView throwing error when subscription wasn't found (#2255)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:34 -03:00
Djorkaeff Alexandre 5cf9291fc9 [FIX] Command previews crashing when API returns an error (#2254)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:29 -03:00
Djorkaeff Alexandre db0520ed7b [FIX] AttachmentView crashing during title decode (#2253)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:53:25 -03:00
Djorkaeff Alexandre 0583de7158 [FIX] Scroll to top crashing when ref is undefined (#2252) 2020-07-08 17:53:17 -03:00
Djorkaeff Alexandre 33edacf087 [FIX] Emoji keyboard not showing custom and frequently used emojis on Share Extension (#2251) 2020-07-08 17:51:24 -03:00
Diego Mello c3a80b6f1e Bump version to 4.8.1 2020-07-08 17:51:09 -03:00
Youssef Muhamad f15c755e03 [FIX] Check for UI_Use_Real_Name when sorting rooms (#2230)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-07-08 17:50:50 -03:00
22 changed files with 159 additions and 116 deletions

View File

@ -139,7 +139,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer versionCode VERSIONCODE as Integer
versionName "4.8.0" versionName "4.8.1"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below! missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!

View File

@ -29,7 +29,8 @@ export default StyleSheet.create({
}, },
handle: { handle: {
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center' alignItems: 'center',
paddingBottom: 8
}, },
handleIndicator: { handleIndicator: {
width: 40, width: 40,

View File

@ -14,17 +14,20 @@ import { Button } from '../ActionSheet';
import { useDimensions } from '../../dimensions'; import { useDimensions } from '../../dimensions';
export const HEADER_HEIGHT = 36; export const HEADER_HEIGHT = 36;
const ITEM_SIZE = 36;
const CONTAINER_MARGIN = 8;
const ITEM_MARGIN = 8;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
alignItems: 'center', alignItems: 'center',
marginHorizontal: 8 marginHorizontal: CONTAINER_MARGIN
}, },
headerItem: { headerItem: {
height: 36, height: ITEM_SIZE,
width: 36, width: ITEM_SIZE,
borderRadius: 20, borderRadius: ITEM_SIZE / 2,
marginHorizontal: 8, marginHorizontal: ITEM_MARGIN,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center' alignItems: 'center'
}, },
@ -84,7 +87,7 @@ HeaderFooter.propTypes = {
}; };
const Header = React.memo(({ const Header = React.memo(({
handleReaction, server, message, theme handleReaction, server, message, isMasterDetail, theme
}) => { }) => {
const [items, setItems] = useState([]); const [items, setItems] = useState([]);
const { width, height } = useDimensions(); const { width, height } = useDimensions();
@ -96,8 +99,8 @@ const Header = React.memo(({
let freqEmojis = await freqEmojiCollection.query().fetch(); let freqEmojis = await freqEmojiCollection.query().fetch();
const isLandscape = width > height; const isLandscape = width > height;
const size = isLandscape ? width / 2 : width; const size = (isLandscape || isMasterDetail ? width / 2 : width) - (CONTAINER_MARGIN * 2);
const quantity = (size / 50) - 1; const quantity = (size / (ITEM_SIZE + (ITEM_MARGIN * 2))) - 1;
freqEmojis = freqEmojis.concat(DEFAULT_EMOJIS).slice(0, quantity); freqEmojis = freqEmojis.concat(DEFAULT_EMOJIS).slice(0, quantity);
setItems(freqEmojis); setItems(freqEmojis);
@ -135,6 +138,7 @@ Header.propTypes = {
handleReaction: PropTypes.func, handleReaction: PropTypes.func,
server: PropTypes.string, server: PropTypes.string,
message: PropTypes.object, message: PropTypes.object,
isMasterDetail: PropTypes.bool,
theme: PropTypes.string theme: PropTypes.string
}; };
export default withTheme(Header); export default withTheme(Header);

View File

@ -32,7 +32,8 @@ const MessageActions = React.memo(forwardRef(({
Message_AllowEditing_BlockEditInMinutes, Message_AllowEditing_BlockEditInMinutes,
Message_AllowPinning, Message_AllowPinning,
Message_AllowStarring, Message_AllowStarring,
Message_Read_Receipt_Store_Users Message_Read_Receipt_Store_Users,
isMasterDetail
}, ref) => { }, ref) => {
let permissions = {}; let permissions = {};
const { showActionSheet, hideActionSheet } = useActionSheet(); const { showActionSheet, hideActionSheet } = useActionSheet();
@ -116,7 +117,12 @@ const MessageActions = React.memo(forwardRef(({
const handleEdit = message => editInit(message); const handleEdit = message => editInit(message);
const handleCreateDiscussion = (message) => { const handleCreateDiscussion = (message) => {
Navigation.navigate('CreateDiscussionView', { message, channel: room }); const params = { message, channel: room, showCloseModal: true };
if (isMasterDetail) {
Navigation.navigate('ModalStackNavigator', { screen: 'CreateDiscussionView', params });
} else {
Navigation.navigate('NewMessageStackNavigator', { screen: 'CreateDiscussionView', params });
}
}; };
const handleUnread = async(message) => { const handleUnread = async(message) => {
@ -377,6 +383,7 @@ const MessageActions = React.memo(forwardRef(({
<Header <Header
server={server} server={server}
handleReaction={handleReaction} handleReaction={handleReaction}
isMasterDetail={isMasterDetail}
message={message} message={message}
/> />
) : null) ) : null)
@ -412,7 +419,8 @@ const mapStateToProps = state => ({
Message_AllowEditing_BlockEditInMinutes: state.settings.Message_AllowEditing_BlockEditInMinutes, Message_AllowEditing_BlockEditInMinutes: state.settings.Message_AllowEditing_BlockEditInMinutes,
Message_AllowPinning: state.settings.Message_AllowPinning, Message_AllowPinning: state.settings.Message_AllowPinning,
Message_AllowStarring: state.settings.Message_AllowStarring, Message_AllowStarring: state.settings.Message_AllowStarring,
Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users,
isMasterDetail: state.app.isMasterDetail
}); });
export default connect(mapStateToProps, null, null, { forwardRef: true })(MessageActions); export default connect(mapStateToProps, null, null, { forwardRef: true })(MessageActions);

View File

@ -17,7 +17,7 @@ export default class EmojiKeyboard extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
const state = store.getState(); const state = store.getState();
this.baseUrl = state.server.server; this.baseUrl = state.share.server || state.server.server;
} }
onEmojiSelected = (emoji) => { onEmojiSelected = (emoji) => {

View File

@ -541,12 +541,14 @@ class MessageBox extends Component {
setCommandPreview = async(command, name, params) => { setCommandPreview = async(command, name, params) => {
const { rid } = this.props; const { rid } = this.props;
try { try {
const { preview } = await RocketChat.getCommandPreview(name, rid, params); const { success, preview } = await RocketChat.getCommandPreview(name, rid, params);
this.setState({ commandPreview: preview.items, showCommandPreview: true, command }); if (success) {
return this.setState({ commandPreview: preview?.items, showCommandPreview: true, command });
}
} catch (e) { } catch (e) {
this.setState({ commandPreview: [], showCommandPreview: true, command: {} });
log(e); log(e);
} }
this.setState({ commandPreview: [], showCommandPreview: true, command: {} });
} }
setInput = (text) => { setInput = (text) => {

View File

@ -110,7 +110,9 @@ class DB {
Thread, Thread,
ThreadMessage, ThreadMessage,
Upload, Upload,
Permission Permission,
CustomEmoji,
FrequentlyUsedEmoji
], ],
actionsEnabled: true actionsEnabled: true
}); });

View File

@ -1,4 +1,3 @@
import { InteractionManager } from 'react-native';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { Q } from '@nozbe/watermelondb'; import { Q } from '@nozbe/watermelondb';
@ -132,48 +131,47 @@ export default async function() {
const filteredSettingsIds = filteredSettings.map(s => s._id); const filteredSettingsIds = filteredSettings.map(s => s._id);
reduxStore.dispatch(addSettings(this.parseSettings(filteredSettings))); reduxStore.dispatch(addSettings(this.parseSettings(filteredSettings)));
InteractionManager.runAfterInteractions(async() => {
// filter server info
const serverInfo = filteredSettings.filter(i1 => serverInfoKeys.includes(i1._id));
const iconSetting = data.find(item => item._id === 'Assets_favicon_512');
await serverInfoUpdate(serverInfo, iconSetting);
await db.action(async() => { // filter server info
const settingsCollection = db.collections.get('settings'); const serverInfo = filteredSettings.filter(i1 => serverInfoKeys.includes(i1._id));
const allSettingsRecords = await settingsCollection const iconSetting = data.find(item => item._id === 'Assets_favicon_512');
.query(Q.where('id', Q.oneOf(filteredSettingsIds))) await serverInfoUpdate(serverInfo, iconSetting);
.fetch();
// filter settings await db.action(async() => {
let settingsToCreate = filteredSettings.filter(i1 => !allSettingsRecords.find(i2 => i1._id === i2.id)); const settingsCollection = db.collections.get('settings');
let settingsToUpdate = allSettingsRecords.filter(i1 => filteredSettings.find(i2 => i1.id === i2._id)); const allSettingsRecords = await settingsCollection
.query(Q.where('id', Q.oneOf(filteredSettingsIds)))
.fetch();
// Create // filter settings
settingsToCreate = settingsToCreate.map(setting => settingsCollection.prepareCreate(protectedFunction((s) => { let settingsToCreate = filteredSettings.filter(i1 => !allSettingsRecords.find(i2 => i1._id === i2.id));
s._raw = sanitizedRaw({ id: setting._id }, settingsCollection.schema); let settingsToUpdate = allSettingsRecords.filter(i1 => filteredSettings.find(i2 => i1.id === i2._id));
Object.assign(s, setting);
})));
// Update // Create
settingsToUpdate = settingsToUpdate.map((setting) => { settingsToCreate = settingsToCreate.map(setting => settingsCollection.prepareCreate(protectedFunction((s) => {
const newSetting = filteredSettings.find(s => s._id === setting.id); s._raw = sanitizedRaw({ id: setting._id }, settingsCollection.schema);
return setting.prepareUpdate(protectedFunction((s) => { Object.assign(s, setting);
Object.assign(s, newSetting); })));
}));
});
const allRecords = [ // Update
...settingsToCreate, settingsToUpdate = settingsToUpdate.map((setting) => {
...settingsToUpdate const newSetting = filteredSettings.find(s => s._id === setting.id);
]; return setting.prepareUpdate(protectedFunction((s) => {
Object.assign(s, newSetting);
try { }));
await db.batch(...allRecords);
} catch (e) {
log(e);
}
return allRecords.length;
}); });
const allRecords = [
...settingsToCreate,
...settingsToUpdate
];
try {
await db.batch(...allRecords);
} catch (e) {
log(e);
}
return allRecords.length;
}); });
} catch (e) { } catch (e) {
log(e); log(e);

View File

@ -288,6 +288,8 @@ const RocketChat = {
const serversDB = database.servers; const serversDB = database.servers;
reduxStore.dispatch(shareSelectServer(server)); reduxStore.dispatch(shareSelectServer(server));
RocketChat.setCustomEmojis();
// set User info // set User info
try { try {
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`); const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
@ -320,7 +322,7 @@ const RocketChat = {
updateJitsiTimeout(roomId) { updateJitsiTimeout(roomId) {
// RC 0.74.0 // RC 0.74.0
return this.post('jitsi.updateTimeout', { roomId }); return this.post('video-conference/jitsi.update-timeout', { roomId });
}, },
register(credentials) { register(credentials) {

View File

@ -260,6 +260,21 @@ function bouncy(
const WIDTH = 300; const WIDTH = 300;
const HEIGHT = 300; const HEIGHT = 300;
class Image extends React.PureComponent {
static propTypes = {
imageComponentType: PropTypes.string
}
render() {
const { imageComponentType } = this.props;
const Component = ImageComponent(imageComponentType);
return <Component {...this.props} />;
}
}
const AnimatedImage = Animated.createAnimatedComponent(Image);
// it was picked from https://github.com/software-mansion/react-native-reanimated/tree/master/Example/imageViewer // it was picked from https://github.com/software-mansion/react-native-reanimated/tree/master/Example/imageViewer
// and changed to use FastImage animated component // and changed to use FastImage animated component
export class ImageViewer extends React.Component { export class ImageViewer extends React.Component {
@ -386,12 +401,9 @@ export class ImageViewer extends React.Component {
render() { render() {
const { const {
uri, width, height, theme, imageComponentType, ...props uri, width, height, imageComponentType, theme, ...props
} = this.props; } = this.props;
const Component = ImageComponent(imageComponentType);
const AnimatedFastImage = Animated.createAnimatedComponent(Component);
// The below two animated values makes it so that scale appears to be done // The below two animated values makes it so that scale appears to be done
// from the top left corner of the image view instead of its center. This // from the top left corner of the image view instead of its center. This
// is required for the "scale focal point" math to work correctly // is required for the "scale focal point" math to work correctly
@ -416,7 +428,7 @@ export class ImageViewer extends React.Component {
onGestureEvent={this._onPanEvent} onGestureEvent={this._onPanEvent}
onHandlerStateChange={this._onPanEvent} onHandlerStateChange={this._onPanEvent}
> >
<AnimatedFastImage <AnimatedImage
style={[ style={[
styles.image, styles.image,
{ {
@ -435,6 +447,7 @@ export class ImageViewer extends React.Component {
] ]
} }
]} ]}
imageComponentType={imageComponentType}
resizeMode='contain' resizeMode='contain'
source={{ uri }} source={{ uri }}
{...props} {...props}

View File

@ -54,8 +54,7 @@ export const FadeFromCenterModal = {
const forStackAndroid = ({ const forStackAndroid = ({
current, current,
inverted, inverted,
layouts: { screen }, layouts: { screen }
closing
}) => { }) => {
const translateX = multiply( const translateX = multiply(
current.progress.interpolate({ current.progress.interpolate({
@ -65,13 +64,12 @@ const forStackAndroid = ({
inverted inverted
); );
const opacity = conditional( const opacity = multiply(
closing,
current.progress,
current.progress.interpolate({ current.progress.interpolate({
inputRange: [0, 1], inputRange: [0, 1],
outputRange: [0, 1] outputRange: [0, 1]
}) }),
inverted
); );
return { return {

View File

@ -46,9 +46,9 @@ export const navigationTheme = (theme) => {
// Gets the current screen from navigation state // Gets the current screen from navigation state
export const getActiveRoute = (state) => { export const getActiveRoute = (state) => {
const route = state.routes[state.index]; const route = state?.routes[state?.index];
if (route.state) { if (route?.state) {
// Dive into nested navigators // Dive into nested navigators
return getActiveRoute(route.state); return getActiveRoute(route.state);
} }
@ -56,4 +56,4 @@ export const getActiveRoute = (state) => {
return route; return route;
}; };
export const getActiveRouteName = state => getActiveRoute(state).name; export const getActiveRouteName = state => getActiveRoute(state)?.name;

View File

@ -70,10 +70,15 @@ class AttachmentView extends React.Component {
setHeader = () => { setHeader = () => {
const { route, navigation, theme } = this.props; const { route, navigation, theme } = this.props;
const attachment = route.params?.attachment; const attachment = route.params?.attachment;
const { title } = attachment; let { title } = attachment;
try {
title = decodeURI(title);
} catch {
// Do nothing
}
const options = { const options = {
title,
headerLeft: () => <CloseModalButton testID='close-attachment-view' navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />, headerLeft: () => <CloseModalButton testID='close-attachment-view' navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />,
title: decodeURI(title),
headerRight: () => <SaveButton testID='save-image' onPress={this.handleSave} buttonStyle={{ color: themes[theme].previewTintColor }} />, headerRight: () => <SaveButton testID='save-image' onPress={this.handleSave} buttonStyle={{ color: themes[theme].previewTintColor }} />,
headerBackground: () => <View style={{ flex: 1, backgroundColor: themes[theme].previewBackground }} />, headerBackground: () => <View style={{ flex: 1, backgroundColor: themes[theme].previewBackground }} />,
headerTintColor: themes[theme].previewTintColor, headerTintColor: themes[theme].previewTintColor,

View File

@ -16,6 +16,7 @@ import RocketChat from '../../lib/rocketchat';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import protectedFunction from '../../lib/methods/helpers/protectedFunction'; import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import SafeAreaView from '../../containers/SafeAreaView'; import SafeAreaView from '../../containers/SafeAreaView';
import log from '../../utils/log';
const SectionTitle = React.memo(({ title, theme }) => ( const SectionTitle = React.memo(({ title, theme }) => (
<Text <Text
@ -183,26 +184,30 @@ class NotificationPreferencesView extends React.Component {
const { room } = this.state; const { room } = this.state;
const db = database.active; const db = database.active;
await db.action(async() => {
await room.update(protectedFunction((r) => {
r[key] = value;
}));
});
try { try {
const result = await RocketChat.saveNotificationSettings(this.rid, params); await db.action(async() => {
if (result.success) { await room.update(protectedFunction((r) => {
return; r[key] = value;
} }));
} catch { });
// do nothing
}
await db.action(async() => { try {
await room.update(protectedFunction((r) => { const result = await RocketChat.saveNotificationSettings(this.rid, params);
r[key] = room[key]; if (result.success) {
})); return;
}); }
} catch {
// do nothing
}
await db.action(async() => {
await room.update(protectedFunction((r) => {
r[key] = room[key];
}));
});
} catch (e) {
log(e);
}
} }
onValueChangeSwitch = (key, value) => this.saveNotificationSettings(key, value, { [key]: value ? '1' : '0' }); onValueChangeSwitch = (key, value) => this.saveNotificationSettings(key, value, { [key]: value ? '1' : '0' });

View File

@ -145,10 +145,12 @@ class RegisterView extends React.Component {
await loginRequest({ user: email, password }); await loginRequest({ user: email, password });
} }
} catch (e) { } catch (e) {
if (e.data && e.data.errorType === 'username-invalid') { if (e.data?.errorType === 'username-invalid') {
return loginRequest({ user: email, password }); return loginRequest({ user: email, password });
} }
showErrorAlert(e.data.error, I18n.t('Oops')); if (e.data?.error) {
showErrorAlert(e.data.error, I18n.t('Oops'));
}
} }
this.setState({ saving: false }); this.setState({ saving: false });
} }

View File

@ -755,7 +755,7 @@ class RoomView extends React.Component {
if (handleCommandScroll(event)) { if (handleCommandScroll(event)) {
const offset = input === 'UIKeyInputUpArrow' ? 100 : -100; const offset = input === 'UIKeyInputUpArrow' ? 100 : -100;
this.offset += offset; this.offset += offset;
this.flatList.scrollToOffset({ offset: this.offset }); this.flatList?.scrollToOffset({ offset: this.offset });
} else if (handleCommandRoomActions(event)) { } else if (handleCommandRoomActions(event)) {
this.goRoomActionsView(); this.goRoomActionsView();
} else if (handleCommandSearchMessages(event)) { } else if (handleCommandSearchMessages(event)) {

View File

@ -411,7 +411,7 @@ class RoomsListView extends React.Component {
let tempChats = []; let tempChats = [];
let chats = []; let chats = [];
if (sortBy === 'alphabetical') { if (sortBy === 'alphabetical') {
chats = orderBy(data, ['name'], ['asc']); chats = orderBy(data, [`${ this.useRealName ? 'fname' : 'name' }`], ['asc']);
} else { } else {
chats = orderBy(data, ['roomUpdatedAt'], ['desc']); chats = orderBy(data, ['roomUpdatedAt'], ['desc']);
} }
@ -504,12 +504,7 @@ class RoomsListView extends React.Component {
closeSearchHeader(); closeSearchHeader();
} }
setTimeout(() => { setTimeout(() => {
const offset = isAndroid ? 0 : SCROLL_OFFSET; this.scrollToTop();
if (this.scroll.scrollTo) {
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
} else if (this.scroll.scrollToOffset) {
this.scroll.scrollToOffset({ offset });
}
}, 200); }, 200);
}); });
}; };
@ -538,9 +533,7 @@ class RoomsListView extends React.Component {
search: result, search: result,
searching: true searching: true
}); });
if (this.scroll && this.scroll.scrollTo) { this.scrollToTop();
this.scroll.scrollTo({ x: 0, y: 0, animated: true });
}
}, 300); }, 300);
getRoomTitle = item => RocketChat.getRoomTitle(item) getRoomTitle = item => RocketChat.getRoomTitle(item)
@ -561,15 +554,17 @@ class RoomsListView extends React.Component {
this.goRoom({ item, isMasterDetail }); this.goRoom({ item, isMasterDetail });
}; };
scrollToTop = () => {
const offset = isAndroid ? 0 : SCROLL_OFFSET;
if (this.scroll?.scrollToOffset) {
this.scroll.scrollToOffset({ offset });
}
}
toggleSort = () => { toggleSort = () => {
const { toggleSortDropdown } = this.props; const { toggleSortDropdown } = this.props;
const offset = isAndroid ? 0 : SCROLL_OFFSET; this.scrollToTop();
if (this.scroll.scrollTo) {
this.scroll.scrollTo({ x: 0, y: offset, animated: true });
} else if (this.scroll.scrollToOffset) {
this.scroll.scrollToOffset({ offset });
}
setTimeout(() => { setTimeout(() => {
toggleSortDropdown(); toggleSortDropdown();
}, 100); }, 100);

View File

@ -123,7 +123,7 @@ class ShareView extends Component {
item.error = error; item.error = error;
// get video thumbnails // get video thumbnails
if (item.mime?.match(/video/)) { if (item.mime?.match?.(/video/)) {
try { try {
const { uri } = await VideoThumbnails.getThumbnailAsync(item.path); const { uri } = await VideoThumbnails.getThumbnailAsync(item.path);
item.uri = uri; item.uri = uri;

View File

@ -141,7 +141,15 @@ class Sidebar extends Component {
get currentItemKey() { get currentItemKey() {
const { state } = this.props; const { state } = this.props;
return state.routeNames[state.index]; return state?.routeNames[state?.index];
}
onPressUser = () => {
const { navigation, isMasterDetail } = this.props;
if (isMasterDetail) {
return;
}
navigation.closeDrawer();
} }
renderAdmin = () => { renderAdmin = () => {
@ -210,7 +218,7 @@ class Sidebar extends Component {
render() { render() {
const { const {
user, Site_Name, baseUrl, useRealName, allowStatusMessage, isMasterDetail, theme, navigation user, Site_Name, baseUrl, useRealName, allowStatusMessage, isMasterDetail, theme
} = this.props; } = this.props;
if (!user) { if (!user) {
@ -229,7 +237,7 @@ class Sidebar extends Component {
]} ]}
{...scrollPersistTaps} {...scrollPersistTaps}
> >
<TouchableWithoutFeedback onPress={() => navigation.closeDrawer()} testID='sidebar-close-drawer'> <TouchableWithoutFeedback onPress={this.onPressUser} testID='sidebar-close-drawer'>
<View style={styles.header} theme={theme}> <View style={styles.header} theme={theme}>
<Avatar <Avatar
text={user.username} text={user.username}

View File

@ -127,7 +127,7 @@ class ThreadMessagesView extends React.Component {
// eslint-disable-next-line react/sort-comp // eslint-disable-next-line react/sort-comp
init = () => { init = () => {
if (!this.subscription) { if (!this.subscription) {
this.load(); return this.load();
} }
try { try {
const lastThreadSync = new Date(); const lastThreadSync = new Date();

View File

@ -19,7 +19,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.8.0</string> <string>4.8.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>XPC!</string> <string>XPC!</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.8.0</string> <string>4.8.1</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>