Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit bb757f3

Browse files
committed
Audio handler & Credit
1 parent 059f036 commit bb757f3

File tree

14 files changed

+448
-74
lines changed

14 files changed

+448
-74
lines changed

app/components/Icon.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,36 @@ import PropTypes from 'prop-types';
33
import { Animated } from 'react-native';
44
import Icons from 'react-native-vector-icons/MaterialIcons';
55
import CommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
6+
import * as Animatable from 'react-native-animatable';
67

78
const CommunityIconsAnimated = Animated.createAnimatedComponent(CommunityIcons);
9+
const CommunityIconsAnimatable = Animatable.createAnimatableComponent(CommunityIcons);
810
const IconsAnimated = Animated.createAnimatedComponent(Icons);
911

10-
export function Icon({ animated, type, innerRef, ...props }) {
12+
export function Icon({ animated, animatable, type, innerRef, ...props }) {
1113
let Comp = Icons;
1214
if (animated) {
1315
Comp = IconsAnimated;
1416
}
15-
if (type === 'community' && !animated) {
17+
if (type === 'community' && !animated && !animatable) {
1618
Comp = CommunityIcons;
1719
} else if (type === 'community' && animated) {
1820
Comp = CommunityIconsAnimated;
21+
} else if (type === 'community' && animatable) {
22+
Comp = CommunityIconsAnimatable;
1923
}
2024

2125
return <Comp ref={innerRef} {...props} />;
2226
}
2327

2428
Icon.propTypes = {
29+
animatable: PropTypes.bool,
2530
animated: PropTypes.bool,
2631
type: PropTypes.oneOf(['community']),
2732
innerRef: PropTypes.func,
2833
};
2934
Icon.defaultProps = {
35+
animatable: false,
3036
animated: false,
3137
type: 'community',
3238
innerRef: () => {},

app/contexts/Settings/index.js

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { createContext, useState, useEffect } from 'react';
1+
import React, { createContext, useState } from 'react';
22
import AsyncStorage from '@react-native-community/async-storage';
3+
import { Player } from '@react-native-community/audio-toolkit';
34
import PropTypes from 'prop-types';
45

56
export const SettingsContext = createContext();
@@ -8,35 +9,75 @@ const KEYS = {
89
MP3: 'default_mp3',
910
};
1011

11-
const mp3s = {
12+
export const MP3S = {
1213
ambient: 'ambient.mp3',
1314
forest: 'forest.mp3',
14-
paino: 'paino.mp3',
15+
paino: 'piano.mp3',
16+
};
17+
18+
const playerConfig = {
19+
continuesToPlayInBackground: false,
20+
autoDestroy: false,
1521
};
1622

1723
export default function SettingsContextProvider({ children }) {
1824
const [state, setState] = useState({
1925
init: false,
20-
defaultMp3: mp3s.paino,
26+
mp3: MP3S.paino,
2127
});
28+
function getNewPlayer(mp3, play = false, cache = false) {
29+
const newPlayer = new Player(mp3, playerConfig);
30+
newPlayer.looping = true;
31+
if (play) {
32+
newPlayer.prepare((err) => {
33+
if (!err) {
34+
newPlayer.play();
35+
}
36+
});
37+
}
38+
if (cache) {
39+
AsyncStorage.setItem(KEYS.MP3, mp3);
40+
}
41+
return newPlayer;
42+
}
43+
const [player, setPlayer] = useState(getNewPlayer(MP3S.paino));
44+
const safeSetState = (newState) => setState({ ...state, ...newState });
45+
const safeSetPlayer = (mp3, ...p) => {
46+
setPlayer(getNewPlayer(mp3, ...p));
47+
safeSetState({ mp3 });
48+
};
2249

2350
async function initApp() {
2451
try {
2552
const cache = await AsyncStorage.getItem(KEYS.MP3);
26-
console.log('CACHE', cache);
27-
setState({ ...state, init: true });
53+
if (cache && cache !== state.mp3) {
54+
safeSetState({ ...state, init: true, mp3: cache });
55+
safeSetPlayer(cache);
56+
} else {
57+
safeSetState({ init: true });
58+
}
2859
} catch (e) {
2960
// e
3061
}
3162
}
3263

33-
useEffect(() => {
34-
if (!state.init) {
35-
initApp();
36-
}
37-
}, [state.init]);
64+
if (!state.init) {
65+
initApp();
66+
}
3867

39-
return <SettingsContext.Provider value={{ ...state }}>{children}</SettingsContext.Provider>;
68+
return (
69+
<SettingsContext.Provider
70+
value={{
71+
...state,
72+
player,
73+
getPlayer: () => player,
74+
setState: safeSetState,
75+
setPlayer: safeSetPlayer,
76+
}}
77+
>
78+
{children}
79+
</SettingsContext.Provider>
80+
);
4081
}
4182

4283
SettingsContextProvider.propTypes = {

app/engine/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { useState, useEffect, useMemo } from 'react';
33
import { captureRef } from 'react-native-view-shot';
44
import share from 'react-native-share';
55

6-
// import { initLayout } from 'utils/ui';
7-
86
import { rotateBox, calculateSuccess, data2Grid } from './utils';
97
import * as UI from './utils/ui';
108

app/index.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,9 @@ function App() {
4444
});
4545

4646
return (
47-
<>
48-
<SettingsContextProvider>
49-
<Navigator onNavigationStateChange={onRouteChange} />
50-
</SettingsContextProvider>
51-
</>
47+
<SettingsContextProvider>
48+
<Navigator onNavigationStateChange={onRouteChange} />
49+
</SettingsContextProvider>
5250
);
5351
}
5452

app/screens/AboutApp/index.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ const links = [
1919
label: 'Original App',
2020
url: 'https://play.google.com/store/apps/details?id=com.balysv.loop',
2121
},
22+
{
23+
icon: 'apple',
24+
label: 'Original App',
25+
url: 'https://apps.apple.com/us/app/infinity-loop-endless-zen/id977028266',
26+
},
27+
{
28+
icon: 'web',
29+
label: 'Orange Free Sounds',
30+
url: 'http://www.orangefreesounds.com/',
31+
},
2232
];
2333

2434
function AboutAppScreen({ navigation }) {
@@ -29,12 +39,15 @@ function AboutAppScreen({ navigation }) {
2939
<Text style={styles.description2}>
3040
I crafted this app becuase I wanted to understand how does loop game calculate result &
3141
figure out a way to implement the game interface in React Native Eco-system as much as
32-
possible with all the good animations & themes. So I implemented first 13 levels with clean
33-
code, good architecture & no redux.
42+
possible with all the good animations & themes. So I implemented few levels with clean code,
43+
good architecture & no redux.
3444
</Text>
3545
<Text style={styles.note}>
3646
Original app & Github code&apos;s link is shared below & any peice of code is free to use
3747
</Text>
48+
<Text style={styles.note}>
49+
All musics are downloaded from orangefreesounds.com. Link is shared below
50+
</Text>
3851
<View style={styles.buttonsHolder}>
3952
{links.map((link) => (
4053
<TouchNative

app/screens/Home/index.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import React from 'react';
1+
import React, { useEffect, useContext } from 'react';
22
import { View, Text } from 'react-native';
3+
import { useIsFocused } from 'react-navigation-hooks';
34
import PropTypes from 'prop-types';
45
import { TouchNative } from 'rn-hgl';
56

7+
import { SettingsContext } from 'contexts/Settings';
8+
69
import PageView from 'components/PageView';
710

811
import styles from './styles';
@@ -15,6 +18,13 @@ const links = [
1518
];
1619

1720
function HomeScreen({ navigation }) {
21+
const isFocused = useIsFocused();
22+
const state = useContext(SettingsContext);
23+
useEffect(() => {
24+
if (isFocused) {
25+
state.player.pause();
26+
}
27+
}, [isFocused]);
1828
return (
1929
<PageView navigation={navigation} style={styles.container}>
2030
<Text style={styles.title}>Welcome</Text>

app/screens/Level/index.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import React, { useRef } from 'react';
1+
import React, { useRef, useContext, useEffect } from 'react';
22
import { View, StatusBar, Animated } from 'react-native';
33
import PropTypes from 'prop-types';
44
import { TouchNative } from 'rn-hgl';
55

6+
import { SettingsContext } from 'contexts/Settings';
7+
68
import PageView from 'components/PageView';
79
import Icon from 'components/Icon';
810

@@ -17,7 +19,7 @@ export default function LevelScreen({ navigation }) {
1719
const { params } = navigation.state;
1820
const forceLevel = parseInt(params.level, 10) || 1;
1921
const { toggle, setToggle } = useToggle();
20-
22+
const state = useContext(SettingsContext);
2123
const {
2224
level,
2325
size,
@@ -31,12 +33,21 @@ export default function LevelScreen({ navigation }) {
3133
} = useEngine(forceLevel, toggle);
3234
const ref = useRef();
3335

36+
useEffect(() => {
37+
if (!state.player.isPlaying) {
38+
state.player.play();
39+
}
40+
return () => {
41+
state.player.pause();
42+
};
43+
}, ['hard-code']);
44+
3445
const bgStyle = { flex: 1, backgroundColor: animateColor('primary', 'primary') };
3546
return (
36-
<Animated.View style={bgStyle}>
47+
<Animated.View ref={ref} style={bgStyle}>
3748
<PageView key={level} navigation={navigation} baseStyle={styles.transparent}>
3849
<StatusBar animated barStyle={success ? 'light-content' : 'dark-content'} />
39-
<View ref={ref} style={[styles.gridContainer]}>
50+
<View style={[styles.gridContainer]}>
4051
<Animated.Text style={[styles.currentLevel, { color: animateColor('accent', 'accent') }]}>
4152
#{level}
4253
</Animated.Text>

0 commit comments

Comments
 (0)