Skip to content

Instantly share code, notes, and snippets.

@kenwheeler
Created August 1, 2017 19:09
Show Gist options
  • Save kenwheeler/8067e58f15f2f06a1ef9464045b0fa32 to your computer and use it in GitHub Desktop.
Save kenwheeler/8067e58f15f2f06a1ef9464045b0fa32 to your computer and use it in GitHub Desktop.
open ReactNative;
type targetDimensions = {
x: float,
y: float,
width: float,
height: float
};
type _state = {
modalTop: Animated.Value.t,
modalLeft: Animated.Value.t,
modalWidth: Animated.Value.t,
modalHeight: Animated.Value.t,
modalOpen: bool,
modalReady: bool,
modalItem: option ScheduleItem.item,
selectedIndex: int,
listOpacity: Animated.Value.t,
targetDimensions
};
let easeIn x => x *. x *. x;
let handleTargetDimensions targetDimensions {ReasonReact.state: state} =>
ReasonReact.Update {...state, targetDimensions};
let handleModal modalOpen {ReasonReact.state: state} => ReasonReact.Update {...state, modalOpen};
let handleModalReady modalReady {ReasonReact.state: state} =>
ReasonReact.Update {...state, modalReady};
let closeModal _ {ReasonReact.state: state} => ReasonReact.Update {...state, modalOpen: false};
let handleItem modalItem {ReasonReact.state: state} =>
ReasonReact.SilentUpdate {...state, modalItem};
let handleIndex selectedIndex {ReasonReact.state: state} =>
ReasonReact.Update {...state, selectedIndex};
let scheduleItemPress self::(self: ReasonReact.self _ _) x y width height item index => {
/* Handle target dimensions */
let fx = float_of_int x;
let fy = float_of_int y;
let fw = float_of_int width;
let fh = float_of_int height;
let targetDimensions = {x: fx, y: fy, width: fw, height: fh};
self.update handleTargetDimensions targetDimensions;
/* Set modal coords based upon clicked item */
Animated.Value.setValue self.state.modalLeft fx;
Animated.Value.setValue self.state.modalTop fy;
Animated.Value.setValue self.state.modalWidth fw;
Animated.Value.setValue self.state.modalHeight fh;
/* Display and give modal data */
self.update handleItem (Some item);
self.update handleIndex index;
self.update handleModal true;
let ww = (DimensionsRe.get `window)##width - 20;
let wh = (DimensionsRe.get `window)##height - 90;
/* Define animations */
let animationBatch =
Animated.parallel
[|
Animated.Timing.animate
value::self.state.listOpacity toValue::(`raw 0.) easing::easeIn duration::300. (),
Animated.Timing.animate
value::self.state.modalTop
toValue::(`raw (PlatformRe.os === PlatformRe.IOS ? 30. : 10.))
easing::easeIn
duration::300.
(),
Animated.Timing.animate
value::self.state.modalWidth
toValue::(`raw (float_of_int ww))
easing::easeIn
duration::300.
(),
Animated.Timing.animate
value::self.state.modalHeight
toValue::(`raw (float_of_int wh))
easing::easeIn
duration::300.
()
|]
[%bs.raw "{stopTogether: true}"];
/* Start animations */
Animated.CompositeAnimation.start
animationBatch
callback::(
fun _ => {
let _id = Js.Global.setTimeout (fun _finished => self.update handleModalReady true) 100;
()
}
)
};
let itemModalPress self::(self: ReasonReact.self _ _) () => {
let animationBatch =
Animated.parallel
[|
Animated.Timing.animate
value::self.state.listOpacity toValue::(`raw 1.) easing::easeIn duration::400. (),
Animated.Timing.animate
value::self.state.modalTop
toValue::(`raw self.state.targetDimensions.y)
easing::easeIn
duration::300.
(),
Animated.Timing.animate
value::self.state.modalWidth
toValue::(`raw self.state.targetDimensions.width)
easing::easeIn
duration::300.
(),
Animated.Timing.animate
value::self.state.modalHeight
toValue::(`raw self.state.targetDimensions.height)
easing::easeIn
duration::300.
()
|]
[%bs.raw "{stopTogether: true}"];
/* Start animations */
Animated.CompositeAnimation.start
animationBatch
callback::(
fun _finished => {
self.update handleModalReady false;
let _ =
Js.Global.setTimeout
(
fun () => {
self.update closeModal ();
Animated.CompositeAnimation.start
(
Animated.Timing.animate
value::self.state.listOpacity
toValue::(`raw 1.)
easing::easeIn
duration::300.
()
)
()
}
)
100;
()
}
)
()
};
let component = ReasonReact.statefulComponent "Schedule";
let styles =
StyleSheet.create
Style.(
{
"container": style [flex 1., alignItems `center, justifyContent `center],
"scrollView": style [flex 1.],
"contentContainer": style [paddingBottom 10.],
"gradient":
style [
flex 1.,
width (float_of_int (DimensionsRe.get `window)##width),
paddingTop (PlatformRe.os === PlatformRe.IOS ? 20. : 0.)
],
"modal": style [position `absolute, bottom 5., right 5., width 25., height 25.]
}
);
let make ::loading ::data=? _children => {
...component,
initialState: fun () => {
listOpacity: Animated.Value.create 1.,
modalOpen: false,
modalReady: false,
modalItem: None,
modalTop: Animated.Value.create 0.,
modalLeft: Animated.Value.create 0.,
modalHeight: Animated.Value.create 0.,
modalWidth: Animated.Value.create 0.,
selectedIndex: 0,
targetDimensions: {x: 0., y: 0., width: 0., height: 0.}
},
render: fun self =>
<View style=styles##container>
<LinearGradient colors=[|"rgb(54, 97, 115)", "rgb(85, 130, 113)"|] style=styles##gradient>
<Animated.View style=Style.(style [opacityAnimated self.state.listOpacity, flex 1.])>
<ScrollView style=styles##scrollView contentContainerStyle=styles##contentContainer>
{
let schedule =
switch data {
| None => [||]
| Some d => d
};
loading == true ?
<ActivityIndicator /> :
Array.mapi
(
fun index item =>
<ScheduleItem
item
index
selectedIndex=self.state.selectedIndex
modalOpen=self.state.modalOpen
key=item##id
onPress=(scheduleItemPress ::self)
/>
)
schedule |> ReasonReact.arrayToElement
}
</ScrollView>
</Animated.View>
</LinearGradient>
(
switch self.state.modalOpen {
| false => ReasonReact.nullElement
| true =>
<Animated.View
style=Style.(
concat [
styles##modal,
style [
position `absolute,
topAnimated self.state.modalTop,
leftAnimated self.state.modalLeft,
widthAnimated self.state.modalWidth,
heightAnimated self.state.modalHeight
/* transformAnimated scaleX::self.state.scale scaleY::self.state.scale () */
]
]
)>
(
switch self.state.modalItem {
| None => ReasonReact.nullElement
| Some item =>
<ItemModal
modalOpen=self.state.modalOpen
modalReady=self.state.modalReady
item
onClose=(itemModalPress ::self)
/>
}
)
</Animated.View>
}
)
</View>
};
let jsComponent =
ReasonReact.wrapReasonForJs
::component
(
fun props =>
make loading::(Js.to_bool props##data##loading) data::props##data##allSchedules [||]
);
let query =
GraphQLTag.gql {|
query allSchedules {
allSchedules {
id
start
talk {
title
speakers {
id
name
bio
photo {
secret
}
}
}
title
}
}
|};
let wrappedComponent = (ReactApollo.graphql ::query) jsComponent;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment