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

Refactor: compute WeekView width dinamically #189

Merged
merged 4 commits into from
Apr 24, 2022
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
84 changes: 45 additions & 39 deletions src/Events/Events.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import NowLine from '../NowLine/NowLine';
import Event from '../Event/Event';
import {
CONTAINER_HEIGHT,
CONTAINER_WIDTH,
calculateDaysArray,
DATE_STR_FORMAT,
availableNumberOfDays,
Expand All @@ -20,11 +19,15 @@ import {
import styles from './Events.styles';

const MINUTES_IN_HOUR = 60;
const EVENT_HORIZONTAL_PADDING = 15;
const EVENTS_CONTAINER_WIDTH = CONTAINER_WIDTH - EVENT_HORIZONTAL_PADDING;
const EVENT_HORIZONTAL_PADDING = 8; // percentage
const MIN_ITEM_WIDTH = 4;
const ALLOW_OVERLAP_SECONDS = 2;

const padItemWidth = (
width,
paddingPercentage = EVENT_HORIZONTAL_PADDING,
) => paddingPercentage > 0 ? width - Math.max(2, width * paddingPercentage / 100) : width;

const areEventsOverlapped = (event1EndDate, event2StartDate) => {
const endDate = moment(event1EndDate);
endDate.subtract(ALLOW_OVERLAP_SECONDS, 'seconds');
Expand Down Expand Up @@ -65,11 +68,9 @@ const addOverlappedToArray = (baseArr, overlappedArr, itemWidth) => {
}

let nLanes;
let horizontalPadding;
let indexToLane;
if (nOverlapped === 2) {
nLanes = nOverlapped;
horizontalPadding = 3;
indexToLane = (index) => index;
} else {
// Distribute events in multiple lanes
Expand Down Expand Up @@ -98,11 +99,10 @@ const addOverlappedToArray = (baseArr, overlappedArr, itemWidth) => {
});

nLanes = Object.keys(latestByLane).length;
horizontalPadding = 2;
indexToLane = (index) => laneByEvent[index];
}
const dividedWidth = itemWidth / nLanes;
const width = Math.max(dividedWidth - horizontalPadding, MIN_ITEM_WIDTH);
const width = Math.max(padItemWidth(dividedWidth, EVENT_HORIZONTAL_PADDING / nLanes), MIN_ITEM_WIDTH);

overlappedArr.forEach((eventWithStyle, index) => {
const { data, style } = eventWithStyle;
Expand All @@ -118,13 +118,14 @@ const addOverlappedToArray = (baseArr, overlappedArr, itemWidth) => {
};

const getEventsWithPosition = (
totalEvents, regularItemWidth, hoursInDisplay, beginAgendaAt,
totalEvents, dayWidth, hoursInDisplay, beginAgendaAt,
) => {
const paddedDayWidth = padItemWidth(dayWidth);
return totalEvents.map((events) => {
let overlappedSoFar = []; // Store events overlapped until now
let lastDate = null;
const eventsWithStyle = events.reduce((eventsAcc, event) => {
const style = getStyleForEvent(event, regularItemWidth, hoursInDisplay, beginAgendaAt);
const style = getStyleForEvent(event, paddedDayWidth, hoursInDisplay, beginAgendaAt);
const eventWithStyle = {
data: event,
style,
Expand All @@ -138,7 +139,7 @@ const getEventsWithPosition = (
addOverlappedToArray(
eventsAcc,
overlappedSoFar,
regularItemWidth,
dayWidth,
);
overlappedSoFar = [eventWithStyle];
lastDate = moment(event.endDate);
Expand All @@ -148,12 +149,34 @@ const getEventsWithPosition = (
addOverlappedToArray(
eventsWithStyle,
overlappedSoFar,
regularItemWidth,
dayWidth,
);
return eventsWithStyle;
});
};

const processEvents = (
eventsByDate, initialDate, numberOfDays, dayWidth, hoursInDisplay,
rightToLeft, beginAgendaAt,
) => {
// totalEvents stores events in each day of numberOfDays
// example: [[event1, event2], [event3, event4], [event5]], each child array
// is events for specific day in range
const dates = calculateDaysArray(initialDate, numberOfDays, rightToLeft);
const totalEvents = dates.map((date) => {
const dateStr = date.format(DATE_STR_FORMAT);
return eventsByDate[dateStr] || [];
});

const totalEventsWithPosition = getEventsWithPosition(
totalEvents,
dayWidth,
hoursInDisplay,
beginAgendaAt,
);
return totalEventsWithPosition;
};

class Events extends PureComponent {
yToHour = (y) => {
const { hoursInDisplay, beginAgendaAt } = this.props;
Expand All @@ -168,30 +191,7 @@ class Events extends PureComponent {
return fullWidth / numberOfDays;
};

processEvents = memoizeOne(
(eventsByDate, initialDate, numberOfDays, hoursInDisplay, rightToLeft,
beginAgendaAt,
) => {
// totalEvents stores events in each day of numberOfDays
// example: [[event1, event2], [event3, event4], [event5]], each child array
// is events for specific day in range
const dates = calculateDaysArray(initialDate, numberOfDays, rightToLeft);
const totalEvents = dates.map((date) => {
const dateStr = date.format(DATE_STR_FORMAT);
return eventsByDate[dateStr] || [];
});

const regularItemWidth = this.getEventItemWidth();

const totalEventsWithPosition = getEventsWithPosition(
totalEvents,
regularItemWidth,
hoursInDisplay,
beginAgendaAt,
);
return totalEventsWithPosition;
},
);
processEvents = memoizeOne(processEvents);

onGridTouch = (event, dayIndex, longPress) => {
const { initialDate, onGridClick, onGridLongPress } = this.props;
Expand Down Expand Up @@ -220,12 +220,13 @@ class Events extends PureComponent {
};

onDragEvent = (event, newX, newY) => {
const { onDragEvent } = this.props;
const { onDragEvent, dayWidth } = this.props;
if (!onDragEvent) {
return;
}

const movedDays = Math.floor(newX / this.getEventItemWidth());
// NOTE: newX is in the eventsColumn coordinates
const movedDays = Math.floor(newX / dayWidth);

const startTime = event.startDate.getTime();
const newStartDate = new Date(startTime);
Expand Down Expand Up @@ -268,19 +269,22 @@ class Events extends PureComponent {
showNowLine,
nowLineColor,
onDragEvent,
dayWidth,
pageWidth,
} = this.props;
const totalEvents = this.processEvents(
eventsByDate,
initialDate,
numberOfDays,
dayWidth,
hoursInDisplay,
rightToLeft,
beginAgendaAt,
);
const timeSlotHeight = getTimeLabelHeight(hoursInDisplay, timeStep);

return (
<View style={styles.container}>
<View style={[styles.container, { width: pageWidth }]}>
{times.map((time) => (
<View
key={time}
Expand All @@ -303,7 +307,7 @@ class Events extends PureComponent {
<NowLine
color={nowLineColor}
hoursInDisplay={hoursInDisplay}
width={this.getEventItemWidth(false)}
width={dayWidth}
beginAgendaAt={beginAgendaAt}
/>
)}
Expand Down Expand Up @@ -359,6 +363,8 @@ Events.propTypes = {
showNowLine: PropTypes.bool,
nowLineColor: PropTypes.string,
onDragEvent: PropTypes.func,
pageWidth: PropTypes.number.isRequired,
dayWidth: PropTypes.number.isRequired,
};

export default Events;
3 changes: 1 addition & 2 deletions src/Events/Events.styles.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { StyleSheet } from 'react-native';
import { CONTAINER_WIDTH, CONTENT_OFFSET } from '../utils';
import { CONTENT_OFFSET } from '../utils';

const GREY_COLOR = '#E9EDF0';

const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: CONTENT_OFFSET,
width: CONTAINER_WIDTH,
},
timeRow: {
flex: 0,
Expand Down
12 changes: 10 additions & 2 deletions src/Times/Times.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import { View, Text } from 'react-native';
import styles from './Times.styles';
import { getTimeLabelHeight } from '../utils';

const Times = ({ times, hoursInDisplay, timeStep, textStyle }) => {
const Times = ({
times, hoursInDisplay, timeStep, textStyle, width,
}) => {
const height = getTimeLabelHeight(hoursInDisplay, timeStep);
return (
<View style={styles.columnContainer}>
<View
style={[
styles.columnContainer,
{ width },
]}
>
{times.map((time) => (
<View key={time} style={[styles.label, { height }]}>
<Text style={[styles.text, textStyle]}>{time}</Text>
Expand All @@ -22,6 +29,7 @@ Times.propTypes = {
hoursInDisplay: PropTypes.number.isRequired,
timeStep: PropTypes.number.isRequired,
textStyle: Text.propTypes.style,
width: PropTypes.number.isRequired,
};

export default React.memo(Times);
1 change: 0 additions & 1 deletion src/Times/Times.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
columnContainer: {
paddingTop: 10,
width: 60,
},
label: {
flex: -1,
Expand Down
5 changes: 3 additions & 2 deletions src/Title/Title.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ const getFontSizeHeader = (numberOfDays) => {
};

const Title = ({
style, showTitle, numberOfDays, selectedDate, textStyle, onMonthPress,
style, showTitle, numberOfDays, selectedDate, textStyle, onMonthPress, width,
}) => {
if (!showTitle) {
return <View style={[styles.title, style]}></View>
}
const formattedMonth = getCurrentMonth(selectedDate);
return (
<TouchableOpacity
style={[styles.title, style]}
style={[styles.title, { width }, style]}
onPress={() => onMonthPress && onMonthPress(selectedDate, formattedMonth)}
disabled={!onMonthPress}
>
Expand All @@ -47,6 +47,7 @@ Title.propTypes = {
style: PropTypes.object,
textStyle: PropTypes.object,
onMonthPress: PropTypes.func,
width: PropTypes.number.isRequired,
};

export default React.memo(Title);
1 change: 0 additions & 1 deletion src/Title/Title.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const styles = StyleSheet.create({
title: {
justifyContent: 'center',
alignItems: 'center',
width: 60,
borderTopWidth: 1,
},
});
Expand Down
38 changes: 28 additions & 10 deletions src/WeekView/WeekView.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import {
DATE_STR_FORMAT,
availableNumberOfDays,
setLocale,
CONTAINER_WIDTH,
minutesToYDimension,
computeWeekViewDimensions,
} from '../utils';

const MINUTES_IN_DAY = 60 * 24;
Expand Down Expand Up @@ -366,11 +366,16 @@ export default class WeekView extends Component {
return sortedEvents;
});

getListItemLayout = (index) => ({
length: CONTAINER_WIDTH,
offset: CONTAINER_WIDTH * index,
index,
});
updateDimensions = memoizeOne(computeWeekViewDimensions);

getListItemLayout = (item, index) => {
const pageWidth = this.dimensions.pageWidth || 0;
return {
length: pageWidth,
offset: pageWidth * index,
index,
};
};

render() {
const {
Expand Down Expand Up @@ -414,6 +419,13 @@ export default class WeekView extends Component {
(prependMostRecent && !rightToLeft) ||
(!prependMostRecent && rightToLeft);

this.dimensions = this.updateDimensions(numberOfDays);
const {
pageWidth,
dayWidth,
timeLabelsWidth,
} = this.dimensions;

return (
<View style={styles.container}>
<View style={styles.headerContainer}>
Expand All @@ -424,6 +436,7 @@ export default class WeekView extends Component {
numberOfDays={numberOfDays}
selectedDate={currentMoment}
onMonthPress={onMonthPress}
width={timeLabelsWidth}
/>
<VirtualizedList
horizontal
Expand All @@ -435,12 +448,12 @@ export default class WeekView extends Component {
data={initialDates}
getItem={(data, index) => data[index]}
getItemCount={(data) => data.length}
getItemLayout={(_, index) => this.getListItemLayout(index)}
getItemLayout={this.getListItemLayout}
keyExtractor={(item) => item}
initialScrollIndex={this.pageOffset}
renderItem={({ item }) => {
return (
<View key={item} style={styles.header}>
<View key={item} style={[styles.header, { width: pageWidth }]}>
<Header
style={headerStyle}
textStyle={headerTextStyle}
Expand All @@ -458,7 +471,9 @@ export default class WeekView extends Component {
/>
</View>
{isRefreshing && RefreshComponent && (
<RefreshComponent style={styles.loadingSpinner} />
<RefreshComponent
style={[styles.loadingSpinner, { right: pageWidth / 2 }]}
/>
)}
<ScrollView
onStartShouldSetResponderCapture={() => false}
Expand All @@ -471,12 +486,13 @@ export default class WeekView extends Component {
textStyle={hourTextStyle}
hoursInDisplay={hoursInDisplay}
timeStep={timeStep}
width={timeLabelsWidth}
/>
<VirtualizedList
data={initialDates}
getItem={(data, index) => data[index]}
getItemCount={(data) => data.length}
getItemLayout={(_, index) => this.getListItemLayout(index)}
getItemLayout={this.getListItemLayout}
keyExtractor={(item) => item}
initialScrollIndex={this.pageOffset}
scrollEnabled={!fixedHorizontally}
Expand Down Expand Up @@ -505,6 +521,8 @@ export default class WeekView extends Component {
showNowLine={showNowLine}
nowLineColor={nowLineColor}
onDragEvent={onDragEvent}
pageWidth={pageWidth}
dayWidth={dayWidth}
/>
);
}}
Expand Down
Loading