Skip to content

Commit

Permalink
Add Landscape support for both platforms (mattermost#909)
Browse files Browse the repository at this point in the history
* Landscape support

* Fix image rotation on Android

* Fix landscape mode for login and login options

* Fix previewer will receive props

* Move device dimensions and others to redux

* Fix unit tests

* Include orientation and tablet in the store
  • Loading branch information
enahum authored and jarredwitt committed Sep 20, 2017
1 parent 59762e4 commit 4995a76
Show file tree
Hide file tree
Showing 57 changed files with 672 additions and 322 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ POD := $(shell command -v pod 2> /dev/null)

.podinstall:
ifdef POD
@echo Getting CocoaPods dependencies;
@echo Getting Cocoapods dependencies;
@cd ios && pod install;
else
@echo "Cocoapods is not installed https://cocoapods.org/"
@exit 1
endif

@touch $@
Expand Down Expand Up @@ -117,6 +120,7 @@ post-install:
@sed -i'' -e 's|"./lib/locales": false|"./lib/locales": "./lib/locales"|g' node_modules/intl-messageformat/package.json
@sed -i'' -e 's|"./lib/locales": false|"./lib/locales": "./lib/locales"|g' node_modules/intl-relativeformat/package.json
@sed -i'' -e 's|"./locale-data/complete.js": false|"./locale-data/complete.js": "./locale-data/complete.js"|g' node_modules/intl/package.json
@sed -i'' -e 's|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);|auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_SENSOR);|g' node_modules/react-native-navigation/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java

start-packager:
@if [ $(shell ps -e | grep -i "cli.js start" | grep -civ grep) -eq 0 ]; then \
Expand Down
3 changes: 3 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<service android:name=".NotificationReplyService"
android:enabled="true"
android:exported="false" />
<activity
android:name="com.reactnativenavigation.controllers.NavigationActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mattermost.rnbeta;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.RestrictionsManager;
Expand All @@ -10,6 +11,7 @@
import android.util.Log;
import android.util.ArraySet;
import android.view.WindowManager.LayoutParams;
import android.content.res.Configuration;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
Expand Down Expand Up @@ -143,6 +145,15 @@ public synchronized void removeVisibilityListener(AppVisibilityListener listener
mListeners.remove(listener);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mVisibleActivity != null) {
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
mVisibleActivity.sendBroadcast(intent);
}
}

private synchronized void switchToVisible(Activity activity) {
if (mVisibleActivity == null) {
mVisibleActivity = activity;
Expand Down
55 changes: 55 additions & 0 deletions app/actions/device/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {Dimensions} from 'react-native';

import {DeviceTypes} from 'app/constants';

export function calculateDeviceDimensions() {
const {height, width} = Dimensions.get('window');
return {
type: DeviceTypes.DEVICE_DIMENSIONS_CHANGED,
data: {
deviceHeight: height,
deviceWidth: width
}
};
}

export function connection(isOnline) {
return async (dispatch, getState) => {
dispatch({
type: DeviceTypes.CONNECTION_CHANGED,
data: isOnline
}, getState);
};
}

export function setStatusBarHeight(height = 20) {
return {
type: DeviceTypes.STATUSBAR_HEIGHT_CHANGED,
data: height
};
}

export function setDeviceOrientation(orientation) {
return {
type: DeviceTypes.DEVICE_ORIENTATION_CHANGED,
data: orientation
};
}

export function setDeviceAsTablet() {
return {
type: DeviceTypes.DEVICE_TYPE_CHANGED,
data: true
};
}

export default {
calculateDeviceDimensions,
connection,
setDeviceOrientation,
setDeviceAsTablet,
setStatusBarHeight
};
13 changes: 0 additions & 13 deletions app/actions/views/connection.js

This file was deleted.

9 changes: 1 addition & 8 deletions app/actions/views/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,6 @@ export function goToNotification(notification) {
};
}

export function setStatusBarHeight(height = 20) {
return {
type: ViewTypes.STATUSBAR_HEIGHT_CHANGED,
data: height
};
}

export function purgeOfflineStore() {
return {type: General.OFFLINE_STORE_PURGE};
}
Expand All @@ -84,5 +77,5 @@ export default {
queueNotification,
clearNotification,
goToNotification,
setStatusBarHeight
purgeOfflineStore
};
53 changes: 42 additions & 11 deletions app/components/channel_drawer/channel_drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {General} from 'mattermost-redux/constants';
import EventEmitter from 'mattermost-redux/utils/event_emitter';

const DRAWER_INITIAL_OFFSET = 40;
const DRAWER_LANDSCAPE_OFFSET = 150;

export default class ChannelDrawer extends PureComponent {
static propTypes = {
Expand All @@ -39,19 +40,29 @@ export default class ChannelDrawer extends PureComponent {
currentChannelId: PropTypes.string.isRequired,
currentTeamId: PropTypes.string.isRequired,
currentUserId: PropTypes.string.isRequired,
isLandscape: PropTypes.bool.isRequired,
isTablet: PropTypes.bool.isRequired,
intl: PropTypes.object.isRequired,
navigator: PropTypes.object,
teamsCount: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired
};

state = {
openDrawer: false,
openDrawerOffset: DRAWER_INITIAL_OFFSET
};

swiperIndex = 1;

constructor(props) {
super(props);

let openDrawerOffset = DRAWER_INITIAL_OFFSET;
if (props.isLandscape || props.isTablet) {
openDrawerOffset = DRAWER_LANDSCAPE_OFFSET;
}
this.state = {
openDrawer: false,
openDrawerOffset
};
}

componentWillMount() {
this.props.actions.getTeams();
}
Expand All @@ -62,6 +73,17 @@ export default class ChannelDrawer extends PureComponent {
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
}

componentWillReceiveProps(nextProps) {
const {isLandscape, isTablet} = this.props;
if (nextProps.isLandscape !== isLandscape || nextProps.isTablet || isTablet) {
let openDrawerOffset = DRAWER_INITIAL_OFFSET;
if (nextProps.isLandscape || nextProps.isTablet) {
openDrawerOffset = DRAWER_LANDSCAPE_OFFSET;
}
this.setState({openDrawerOffset});
}
}

componentWillUnmount() {
EventEmitter.off('open_channel_drawer', this.openChannelDrawer);
EventEmitter.off('close_channel_drawer', this.closeChannelDrawer);
Expand All @@ -81,6 +103,10 @@ export default class ChannelDrawer extends PureComponent {
this.setState({openDrawer: false});
};

drawerSwiperRef = (ref) => {
this.drawerSwiper = ref;
};

handleDrawerClose = () => {
this.resetDrawer();

Expand All @@ -93,7 +119,7 @@ export default class ChannelDrawer extends PureComponent {
};

handleDrawerOpen = () => {
if (this.state.openDrawerOffset === DRAWER_INITIAL_OFFSET) {
if (this.state.openDrawerOffset !== 0) {
Keyboard.dismiss();
}
};
Expand Down Expand Up @@ -210,8 +236,13 @@ export default class ChannelDrawer extends PureComponent {

onSearchEnds = () => {
//hack to update the drawer when the offset changes
const {isLandscape, isTablet} = this.props;
this.refs.drawer._syncAfterUpdate = true; //eslint-disable-line no-underscore-dangle
this.setState({openDrawerOffset: DRAWER_INITIAL_OFFSET});
let openDrawerOffset = DRAWER_INITIAL_OFFSET;
if (isLandscape || isTablet) {
openDrawerOffset = DRAWER_LANDSCAPE_OFFSET;
}
this.setState({openDrawerOffset});
};

onSearchStart = () => {
Expand All @@ -221,13 +252,13 @@ export default class ChannelDrawer extends PureComponent {

showTeams = () => {
if (this.swiperIndex === 1 && this.props.teamsCount > 1) {
this.refs.swiper.showTeamsPage();
this.drawerSwiper.getWrappedInstance().showTeamsPage();
}
};

resetDrawer = () => {
if (this.swiperIndex !== 1) {
this.refs.swiper.resetPage();
this.drawerSwiper.getWrappedInstance().resetPage();
}
};

Expand All @@ -242,7 +273,7 @@ export default class ChannelDrawer extends PureComponent {
openDrawerOffset
} = this.state;

const showTeams = openDrawerOffset === DRAWER_INITIAL_OFFSET && teamsCount > 1;
const showTeams = openDrawerOffset !== 0 && teamsCount > 1;

const teams = (
<View style={style.swiperContent}>
Expand All @@ -268,7 +299,7 @@ export default class ChannelDrawer extends PureComponent {

return (
<DrawerSwiper
ref='swiper'
ref={this.drawerSwiperRef}
onPageSelected={this.onPageSelected}
openDrawerOffset={openDrawerOffset}
showTeams={showTeams}
Expand Down
93 changes: 93 additions & 0 deletions app/components/channel_drawer/drawer_swipper/drawer_swiper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import Swiper from 'react-native-swiper';

import {changeOpacity} from 'app/utils/theme';

export default class DrawerSwiper extends PureComponent {
static propTypes = {
children: PropTypes.node.isRequired,
deviceHeight: PropTypes.number.isRequired,
deviceWidth: PropTypes.number.isRequired,
isLandscape: PropTypes.bool.isRequired,
onPageSelected: PropTypes.func,
openDrawerOffset: PropTypes.number,
showTeams: PropTypes.bool.isRequired,
theme: PropTypes.object.isRequired
};

static defaultProps = {
onPageSelected: () => true,
openDrawerOffset: 0
};

state = {
index: 1
};

componentWillReceiveProps(nextProps) {
if (this.refs.swiper) {
if (nextProps.openDrawerOffset !== this.props.openDrawerOffset || nextProps.isLandscape !== this.props.isLandscape) {
this.refs.swiper.initialRender = true;
if (this.state.index === 1) {
this.resetPage();
}
}
}
}

swiperPageSelected = (e, state, context) => {
this.props.onPageSelected(context.state.index);
this.setState({index: context.state.index});
};

showTeamsPage = () => {
this.refs.swiper.scrollBy(-1, true);
};

resetPage = () => {
this.refs.swiper.scrollBy(1, false);
};

render() {
const {
children,
deviceHeight,
deviceWidth,
openDrawerOffset,
showTeams,
theme
} = this.props;

const pagination = {bottom: 0};
if (showTeams) {
pagination.bottom = 0;
}

return (
<Swiper
ref='swiper'
horizontal={true}
loop={false}
index={this.state.index}
onMomentumScrollEnd={this.swiperPageSelected}
paginationStyle={[{position: 'absolute'}, pagination]}
width={deviceWidth - openDrawerOffset}
height={deviceHeight}
style={{backgroundColor: theme.sidebarBg}}
activeDotColor={theme.sidebarText}
dotColor={changeOpacity(theme.sidebarText, 0.5)}
removeClippedSubviews={true}
automaticallyAdjustContentInsets={true}
scrollEnabled={showTeams}
showsPagination={showTeams}
keyboardShouldPersistTaps={'always'}
>
{children}
</Swiper>
);
}
}
Loading

0 comments on commit 4995a76

Please sign in to comment.