Created
August 1, 2017 14:29
-
-
Save kenwheeler/3823c20b07e6d0d85abd64e03a00cfba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
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 scheduleItemPress self::(self: ReasonReact.self _ _) x y width height item => { | |
/* 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 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.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 => { | |
let _ = | |
Js.Global.setTimeout | |
( | |
fun () => | |
Animated.CompositeAnimation.start | |
( | |
Animated.Timing.animate | |
value::self.state.listOpacity | |
toValue::(`raw 1.) | |
easing::easeIn | |
duration::300. | |
() | |
) | |
callback::( | |
fun _finished => { | |
self.update handleModalReady false; | |
self.update closeModal () | |
} | |
) | |
() | |
) | |
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., | |
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.map | |
( | |
fun item => | |
<ScheduleItem item 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