Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable landscape orientation for android #64

Merged
merged 4 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:screenOrientation="unspecified"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
21 changes: 13 additions & 8 deletions src/components/BottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState, useCallback, useRef} from 'react';
import {View, StyleSheet, TouchableHighlight, TouchableOpacity} from 'react-native';
import React, {useState, useCallback, useRef, useEffect} from 'react';
import {View, StyleSheet, TouchableHighlight, TouchableOpacity, useWindowDimensions} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeArea} from 'react-native-safe-area-context';
import BottomSheetRaw from 'reanimated-bottom-sheet';
Expand All @@ -19,7 +19,9 @@ interface ContentProps {
const SheetContentsContainer = ({children, isExpanded, toggleExpanded}: ContentProps) => {
const content = (
<Box backgroundColor="overlayBackground" minHeight="100%">
<Box marginTop="l">{children}</Box>
<Box marginTop="l" alignItems="center">
{children}
</Box>
</Box>
);

Expand All @@ -36,9 +38,6 @@ export interface BottomSheetProps {
extraContent?: boolean;
}

const SNAP_POINTS = ['100%', '20%'];
const SNAP_POINTS_LARGE = ['100%', '30%'];

export const BottomSheet = ({children, collapsedContent, extraContent}: BottomSheetProps) => {
const bottomSheetPosition = useRef(new Animated.Value(1));
const bottomSheetRef: React.Ref<BottomSheetRaw> = useRef(null);
Expand All @@ -58,6 +57,13 @@ export const BottomSheet = ({children, collapsedContent, extraContent}: BottomSh
const onOpenEnd = useCallback(() => setIsExpanded(true), []);
const onCloseEnd = useCallback(() => setIsExpanded(false), []);

const {width, height} = useWindowDimensions();
const snapPoints = [height, Math.max(width, height) * (extraContent ? 0.3 : 0.2)];

useEffect(() => {
bottomSheetRef.current?.snapTo(isExpanded ? 0 : 1);
}, [width, isExpanded]);
Comment on lines +63 to +65
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't ideal - unfortunately without it when the bottom sheet is collapsed, on rotation it sometimes would disappear.


const expandedContentWrapper = (
<Animated.View style={{opacity: abs(sub(bottomSheetPosition.current, 1))}}>
{children}
Expand Down Expand Up @@ -89,8 +95,6 @@ export const BottomSheet = ({children, collapsedContent, extraContent}: BottomSh
);
}, [collapsedContentWrapper, expandedContentWrapper, isExpanded, toggleExpanded]);

const snapPoints = extraContent ? SNAP_POINTS_LARGE : SNAP_POINTS;

return (
<>
<BottomSheetRaw
Expand All @@ -104,6 +108,7 @@ export const BottomSheet = ({children, collapsedContent, extraContent}: BottomSh
snapPoints={snapPoints}
initialSnap={1}
callbackNode={bottomSheetPosition.current}
enabledInnerScrolling
/>
<Box height={snapPoints[1]} style={styles.spacer} />
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const Header = ({isOverlay}: HeaderProps) => {
}, [navigation]);
return (
<TouchableWithoutFeedback onPress={onLogoPress}>
<Box flexDirection="row" alignItems="center" justifyContent="center" marginBottom="m">
<Box flexDirection="row" alignItems="center" justifyContent="center" marginBottom="l">
<Box marginHorizontal="s">
<Icon size={20} name="shield-covid" />
</Box>
Expand Down
8 changes: 6 additions & 2 deletions src/screens/home/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {useExposureStatus, useSystemStatus, SystemStatus} from 'services/Exposur
import {checkNotifications, requestNotifications} from 'react-native-permissions';
import {useNetInfo} from '@react-native-community/netinfo';
import {useNavigation, DrawerActions} from '@react-navigation/native';
import {useMaxContentWidth} from 'shared/useMaxContentWidth';

import {ExposureNotificationsDisabledView} from './views/ExposureNotificationsDisabledView';
import {BluetoothDisabledView} from './views/BluetoothDisabledView';
Expand Down Expand Up @@ -109,9 +110,11 @@ export const HomeScreen = () => {
[showNotificationWarning, systemStatus, turnNotificationsOn],
);

const maxWidth = useMaxContentWidth();

return (
<Box flex={1} backgroundColor="mainBackground">
<Box flex={1} paddingTop="m">
<Box flex={1} alignItems="center" backgroundColor="mainBackground">
<Box flex={1} maxWidth={maxWidth} paddingTop="m">
<Content />
</Box>
<BottomSheet
Expand All @@ -124,6 +127,7 @@ export const HomeScreen = () => {
status={systemStatus}
notificationWarning={showNotificationWarning}
turnNotificationsOn={turnNotificationsOn}
maxWidth={maxWidth}
/>
</BottomSheet>
</Box>
Expand Down
39 changes: 24 additions & 15 deletions src/screens/home/components/BaseHomeView.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
import React from 'react';
import {StyleSheet, Dimensions, ScrollView} from 'react-native';
import {StyleSheet, ScrollView} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import LottieView from 'lottie-react-native';
import {Box, Header} from 'components';

const {width: viewportWidth, height: viewportHeight} = Dimensions.get('window');
import {useOrientation} from 'shared/useOrientation';

interface BaseHomeViewProps {
children?: React.ReactNode;
animationSource?: string;
}

export const BaseHomeView = ({children, animationSource}: BaseHomeViewProps) => {
const {
orientation,
scaledSize: {width: viewportWidth, height: viewportHeight},
} = useOrientation();

return (
<SafeAreaView style={styles.flex}>
<Header />
<ScrollView
style={styles.flex}
contentContainerStyle={[styles.scrollContainer, animationSource ? styles.scrollContainerWithAnimation : null]}
contentContainerStyle={[
styles.scrollContainer,
animationSource && orientation === 'portrait' ? styles.scrollContainerWithAnimation : null,
]}
bounces={false}
>
{animationSource && (
<LottieView
style={{
...styles.animationBase,
width: viewportWidth * 2,
height: viewportHeight / 2,
}}
source={animationSource}
autoPlay
loop
/>
{animationSource && orientation === 'portrait' && (
<Box marginBottom="m">
<LottieView
style={{
...styles.animationBase,
width: viewportWidth * 2,
height: viewportHeight / 2,
}}
source={animationSource}
autoPlay
loop
/>
</Box>
)}
<Box flex={1} alignItems="center" justifyContent="center" marginHorizontal="xl">
{children}
Expand Down
8 changes: 4 additions & 4 deletions src/screens/home/views/OverlayView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback} from 'react';
import {Linking} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {Box, InfoBlock} from 'components';
import {Box, InfoBlock, BoxProps} from 'components';
import {useI18n, I18n} from '@shopify/react-i18n';
import {SystemStatus} from 'services/ExposureNotificationService';

Expand Down Expand Up @@ -56,18 +56,18 @@ const NotificationStatusOff = ({action, i18n}: {action: () => void; i18n: I18n})
);
};

interface Props {
interface Props extends Pick<BoxProps, 'maxWidth'> {
status: SystemStatus;
notificationWarning: boolean;
turnNotificationsOn: () => void;
}

export const OverlayView = ({status, notificationWarning, turnNotificationsOn}: Props) => {
export const OverlayView = ({status, notificationWarning, turnNotificationsOn, maxWidth}: Props) => {
const [i18n] = useI18n();
const navigation = useNavigation();

return (
<Box>
<Box maxWidth={maxWidth}>
<Box marginBottom="l">
<StatusHeaderView enabled={status === SystemStatus.Active} />
</Box>
Expand Down
23 changes: 16 additions & 7 deletions src/screens/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React, {useCallback, useRef, useState} from 'react';
import {useNavigation} from '@react-navigation/native';
import {Box, Button, ProgressCircles, Header, LanguageToggle} from 'components';
import {Dimensions, StyleSheet} from 'react-native';
import {StyleSheet, useWindowDimensions} from 'react-native';
import {SafeAreaView, useSafeArea} from 'react-native-safe-area-context';
import Carousel, {CarouselStatic} from 'react-native-snap-carousel';
import {useStorage} from 'services/StorageService';
import {useI18n} from '@shopify/react-i18n';
import OnboardingBg from 'assets/onboarding-bg.svg';
import {useMaxContentWidth} from 'shared/useMaxContentWidth';

import {Permissions} from './views/Permissions';
import {Start} from './views/Start';

const {width: viewportWidth} = Dimensions.get('window');

type ViewKey = 'start' | 'permissions';

const contentData: ViewKey[] = ['start', 'permissions'];
Expand All @@ -23,6 +22,7 @@ const viewComponents = {

export const OnboardingScreen = () => {
const [i18n] = useI18n();
const {width: viewportWidth} = useWindowDimensions();
const insets = useSafeArea();
const [currentIndex, setCurrentIndex] = useState(0);
const carouselRef = useRef(null);
Expand All @@ -37,10 +37,19 @@ export const OnboardingScreen = () => {
});
}, [navigation, setOnboarded]);

const renderItem = useCallback(({item}: {item: ViewKey}) => {
const ItemComponent = viewComponents[item];
return <ItemComponent />;
}, []);
const maxWidth = useMaxContentWidth();

const renderItem = useCallback(
({item}: {item: ViewKey}) => {
const ItemComponent = viewComponents[item];
return (
<Box maxWidth={maxWidth} alignSelf="center">
<ItemComponent />
</Box>
);
},
[maxWidth],
);

const nextItem = useCallback(() => {
if (carouselRef.current) {
Expand Down
5 changes: 2 additions & 3 deletions src/screens/tutorial/Tutorial.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useState, useCallback, useRef} from 'react';
import {Dimensions, StyleSheet} from 'react-native';
import {StyleSheet, useWindowDimensions} from 'react-native';
import Carousel, {CarouselStatic} from 'react-native-snap-carousel';
import {useNavigation} from '@react-navigation/native';
import {Box, Button, ProgressCircles, Toolbar} from 'components';
Expand All @@ -8,10 +8,9 @@ import {useI18n} from '@shopify/react-i18n';

import {TutorialContent, tutorialData, TutorialKey} from './TutorialContent';

const {width: viewportWidth} = Dimensions.get('window');

export const TutorialScreen = () => {
const navigation = useNavigation();
const {width: viewportWidth} = useWindowDimensions();
const carouselRef = useRef(null);
const [currentStep, setCurrentStep] = useState(0);
const [i18n] = useI18n();
Expand Down
5 changes: 2 additions & 3 deletions src/screens/tutorial/TutorialContent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, {useRef, useEffect} from 'react';
import {Dimensions, StyleSheet, ScrollView} from 'react-native';
import {StyleSheet, ScrollView, useWindowDimensions} from 'react-native';
import {Box, Text} from 'components';
import {useI18n} from '@shopify/react-i18n';
import LottieView from 'lottie-react-native';

const {width: viewportWidth, height: viewportHeight} = Dimensions.get('window');

export type TutorialKey = 'step-1' | 'step-2' | 'step-3';

export const tutorialData: TutorialKey[] = ['step-1', 'step-2', 'step-3'];
Expand All @@ -18,6 +16,7 @@ const animationData = {

export const TutorialContent = ({item, isActiveSlide}: {item: TutorialKey; isActiveSlide: boolean}) => {
const [i18n] = useI18n();
const {width: viewportWidth, height: viewportHeight} = useWindowDimensions();
const animationRef: React.Ref<LottieView> = useRef(null);
useEffect(() => {
if (isActiveSlide) {
Expand Down
1 change: 1 addition & 0 deletions src/shared/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ const theme = {
disabled: {},
},
},
maxContentWidth: 500,
};

export type Theme = typeof theme;
Expand Down
10 changes: 10 additions & 0 deletions src/shared/useMaxContentWidth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {useTheme} from '@shopify/restyle';

import {useOrientation} from './useOrientation';
import {Theme} from './theme';

export const useMaxContentWidth = (): number | undefined => {
Copy link
Contributor Author

@sbearben sbearben May 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rationale for this hook is that if we later want to change how the maxWidth is determined (say, maybe percentage of viewport), we can just make the modification here.

const {maxContentWidth} = useTheme<Theme>();
const {orientation} = useOrientation();
return orientation === 'landscape' ? maxContentWidth : undefined;
};
13 changes: 13 additions & 0 deletions src/shared/useOrientation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {useWindowDimensions, ScaledSize} from 'react-native';

type Orientation = 'portrait' | 'landscape';

interface OrientationReturnValue {
orientation: Orientation;
scaledSize: ScaledSize;
}

export const useOrientation = (): OrientationReturnValue => {
const scaledSize = useWindowDimensions();
return {orientation: scaledSize.width > scaledSize.height ? 'landscape' : 'portrait', scaledSize};
};