Added placeholder task info and made some UI/UX improvements
This commit is contained in:
@@ -19,32 +19,55 @@ const colors = {
|
|||||||
const timers = [...Array(13).keys()].map((i) => (i === 0 ? 1 : i * 5));
|
const timers = [...Array(13).keys()].map((i) => (i === 0 ? 1 : i * 5));
|
||||||
const ITEM_SIZE = width * 0.38;
|
const ITEM_SIZE = width * 0.38;
|
||||||
const ITEM_SPACING = (width - ITEM_SIZE) / 2;
|
const ITEM_SPACING = (width - ITEM_SIZE) / 2;
|
||||||
|
const TIMER_UNIT_IN_SECONDS = 1; // Set to 60 for timer value to represent minutes
|
||||||
const placeholderTask = {
|
const placeholderTask = {
|
||||||
name: 'Read chapter 4',
|
name: 'Read chapter 4',
|
||||||
description: 'Focus on the summary questions and write down anything unclear.',
|
description: 'Focus on the summary questions and write down anything unclear.',
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
function formatTime(totalSeconds: number) {
|
||||||
Har bare skrevet timeren som en egen tab til å begynne med.
|
const minutes = Math.floor(totalSeconds / 60);
|
||||||
Planen er at når bruker starter en task så vil de få opp denne timeren
|
const seconds = totalSeconds % 60;
|
||||||
som viser TaskName og Description der tallene står nå
|
|
||||||
Kanskje en animert figur hvis vi får tid
|
return `${minutes.toString().padStart(2, '0')}:${
|
||||||
*/
|
seconds.toString().padStart(2, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [containerHeight, setContainerHeight] = React.useState(0)
|
const [containerHeight, setContainerHeight] = React.useState(0)
|
||||||
const scrollX = React.useRef(new Animated.Value(0)).current;
|
|
||||||
const [duration, setDuration] = React.useState(timers[0])
|
const [duration, setDuration] = React.useState(timers[0])
|
||||||
const [isRunning, setIsRunning] = React.useState(false)
|
const [isRunning, setIsRunning] = React.useState(false)
|
||||||
|
const [timeRemaining, setTimeRemaining] = React.useState(0)
|
||||||
|
const [selectedIndex, setSelectedIndex] = React.useState(0)
|
||||||
|
const [showCountdownText, setShowCountdownText] = React.useState(false)
|
||||||
|
const scrollX = React.useRef(new Animated.Value(0)).current;
|
||||||
const timerAnimation = React.useRef(new Animated.Value(0)).current
|
const timerAnimation = React.useRef(new Animated.Value(0)).current
|
||||||
const buttonAnimation = React.useRef(new Animated.Value(0)).current
|
const buttonAnimation = React.useRef(new Animated.Value(0)).current
|
||||||
const taskDetailsAnimation = React.useRef(new Animated.Value(0)).current
|
const taskDetailsAnimation = React.useRef(new Animated.Value(0)).current
|
||||||
|
const countdownAnimation = React.useRef(new Animated.Value(0)).current
|
||||||
|
|
||||||
const animation = React.useCallback(() => {
|
const animation = React.useCallback(() => {
|
||||||
if (isRunning) {
|
if (isRunning || containerHeight === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsRunning(true);
|
setIsRunning(true);
|
||||||
|
setShowCountdownText(true);
|
||||||
taskDetailsAnimation.setValue(0);
|
taskDetailsAnimation.setValue(0);
|
||||||
|
countdownAnimation.setValue(0);
|
||||||
|
|
||||||
|
const totalSeconds = duration * TIMER_UNIT_IN_SECONDS;
|
||||||
|
setTimeRemaining(totalSeconds);
|
||||||
|
|
||||||
|
const countdown = setInterval(() => {
|
||||||
|
setTimeRemaining((currentTime) => {
|
||||||
|
if (currentTime <= 1) {
|
||||||
|
clearInterval(countdown)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return currentTime -1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
Animated.sequence([
|
Animated.sequence([
|
||||||
Animated.parallel([
|
Animated.parallel([
|
||||||
@@ -58,6 +81,11 @@ export default function App() {
|
|||||||
duration: 500,
|
duration: 500,
|
||||||
useNativeDriver: true
|
useNativeDriver: true
|
||||||
}),
|
}),
|
||||||
|
Animated.timing(countdownAnimation, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 300,
|
||||||
|
useNativeDriver: true
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
Animated.timing(timerAnimation, {
|
Animated.timing(timerAnimation, {
|
||||||
toValue: 0,
|
toValue: 0,
|
||||||
@@ -66,37 +94,45 @@ export default function App() {
|
|||||||
}),
|
}),
|
||||||
Animated.timing(timerAnimation, {
|
Animated.timing(timerAnimation, {
|
||||||
toValue: containerHeight,
|
toValue: containerHeight,
|
||||||
duration: duration * 1000,
|
duration: totalSeconds * 1000,
|
||||||
useNativeDriver: true
|
useNativeDriver: true
|
||||||
}),
|
})
|
||||||
]) .start(({ finished }) => {
|
]).start(({ finished }) => {
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
setIsRunning(false);
|
setIsRunning(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Animated.timing(countdownAnimation, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 200,
|
||||||
|
useNativeDriver: true
|
||||||
|
}).start(() => {
|
||||||
|
setShowCountdownText(false);
|
||||||
|
|
||||||
Animated.parallel([
|
Animated.parallel([
|
||||||
Animated.timing(buttonAnimation, {
|
Animated.timing(buttonAnimation, {
|
||||||
toValue: 0,
|
toValue: 0,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
useNativeDriver: true
|
useNativeDriver: true
|
||||||
}),
|
}),
|
||||||
Animated.timing(taskDetailsAnimation, {
|
Animated.timing(taskDetailsAnimation, {
|
||||||
toValue: 0,
|
toValue: 0,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
useNativeDriver: true
|
useNativeDriver: true
|
||||||
}),
|
}),
|
||||||
]).start(() => {
|
]).start(() => {
|
||||||
setIsRunning(false);
|
setIsRunning(false);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, [buttonAnimation, duration, isRunning, taskDetailsAnimation, timerAnimation])
|
})
|
||||||
|
}, [countdownAnimation, buttonAnimation, containerHeight, duration, isRunning, taskDetailsAnimation, timerAnimation])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (containerHeight > 0) {
|
if (containerHeight > 0 && !isRunning) {
|
||||||
timerAnimation.setValue(containerHeight);
|
timerAnimation.setValue(containerHeight);
|
||||||
}
|
}
|
||||||
})
|
}, [containerHeight, isRunning, timerAnimation])
|
||||||
|
|
||||||
const opacity = buttonAnimation.interpolate({
|
const opacity = buttonAnimation.interpolate({
|
||||||
inputRange: [0, 1],
|
inputRange: [0, 1],
|
||||||
@@ -127,7 +163,7 @@ return (
|
|||||||
<StatusBar hidden />
|
<StatusBar hidden />
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[StyleSheet.absoluteFillObject, {
|
style={[StyleSheet.absoluteFillObject, {
|
||||||
height,
|
height: containerHeight,
|
||||||
width,
|
width,
|
||||||
backgroundColor: colors.red,
|
backgroundColor: colors.red,
|
||||||
transform: [{
|
transform: [{
|
||||||
@@ -176,8 +212,10 @@ return (
|
|||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
onMomentumScrollEnd={ev => {
|
onMomentumScrollEnd={ev => {
|
||||||
const index = Math.round(ev.nativeEvent.contentOffset.x / ITEM_SIZE)
|
const index = Math.round(ev.nativeEvent.contentOffset.x / ITEM_SIZE)
|
||||||
|
setSelectedIndex(index);
|
||||||
setDuration(timers[index]);
|
setDuration(timers[index]);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
snapToInterval={ITEM_SIZE}
|
snapToInterval={ITEM_SIZE}
|
||||||
decelerationRate={"fast"}
|
decelerationRate={"fast"}
|
||||||
style={{flexGrow: 0}}
|
style={{flexGrow: 0}}
|
||||||
@@ -185,11 +223,14 @@ return (
|
|||||||
paddingHorizontal: ITEM_SPACING
|
paddingHorizontal: ITEM_SPACING
|
||||||
}}
|
}}
|
||||||
renderItem={({item, index}) => {
|
renderItem={({item, index}) => {
|
||||||
|
const isSelected = index === selectedIndex;
|
||||||
|
const timerText = showCountdownText && isSelected ? formatTime(timeRemaining) : item;
|
||||||
const inputRange = [
|
const inputRange = [
|
||||||
(index - 1) * ITEM_SIZE,
|
(index - 1) * ITEM_SIZE,
|
||||||
index * ITEM_SIZE,
|
index * ITEM_SIZE,
|
||||||
(index + 1) * ITEM_SIZE,
|
(index + 1) * ITEM_SIZE,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
const normalOpacity = scrollX.interpolate({
|
const normalOpacity = scrollX.interpolate({
|
||||||
inputRange,
|
inputRange,
|
||||||
@@ -202,21 +243,21 @@ return (
|
|||||||
})
|
})
|
||||||
const opacity = Animated.add(
|
const opacity = Animated.add(
|
||||||
Animated.multiply(normalOpacity, inactiveTimerNumberOpacity),
|
Animated.multiply(normalOpacity, inactiveTimerNumberOpacity),
|
||||||
Animated.multiply(selectedOpacity, buttonAnimation)
|
Animated.multiply(selectedOpacity, countdownAnimation)
|
||||||
)
|
)
|
||||||
const scale = scrollX.interpolate({
|
const scale = scrollX.interpolate({
|
||||||
inputRange,
|
inputRange,
|
||||||
outputRange: [.7, 1, .7]
|
outputRange: [.7, 1, .7]
|
||||||
})
|
})
|
||||||
return <View style={{width: ITEM_SIZE, justifyContent: 'center', alignItems: 'center'}}>
|
return <View style={{width: ITEM_SIZE, justifyContent: 'center', alignItems: 'center'}}>
|
||||||
<Animated.Text style={[styles.text, {
|
<Animated.Text style={[showCountdownText && isSelected ? styles.countdownText : styles.text, {
|
||||||
opacity,
|
opacity,
|
||||||
transform: [{
|
transform: [{
|
||||||
scale
|
scale
|
||||||
}]
|
}]
|
||||||
|
|
||||||
}]}>
|
}]}>
|
||||||
{item}
|
{timerText}
|
||||||
</Animated.Text>
|
</Animated.Text>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
@@ -251,6 +292,7 @@ const styles = StyleSheet.create({
|
|||||||
height: 80,
|
height: 80,
|
||||||
borderRadius: 80,
|
borderRadius: 80,
|
||||||
backgroundColor: colors.red,
|
backgroundColor: colors.red,
|
||||||
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: ITEM_SIZE * 0.8,
|
fontSize: ITEM_SIZE * 0.8,
|
||||||
@@ -277,5 +319,11 @@ const styles = StyleSheet.create({
|
|||||||
lineHeight: 22,
|
lineHeight: 22,
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
countdownText: {
|
||||||
|
fontSize: ITEM_SIZE * 0.32,
|
||||||
|
fontFamily: 'Menlo',
|
||||||
|
color: colors.text,
|
||||||
|
fontWeight: '900',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user