Skip to content

Commit 325158c

Browse files
Implement app theming so we can mirror the users look and feel of the desktop client
1 parent 9ecd5be commit 325158c

File tree

13 files changed

+144
-50
lines changed

13 files changed

+144
-50
lines changed

android/app/src/main/res/values/styles.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<!-- Base application theme. -->
44
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
55
<!-- Customize your theme here. -->
6+
<item name="android:textColorSecondary">@android:color/white</item>
67
</style>
78

89
</resources>

src/app.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import HomeScreen from './screens/HomeScreen'
55
import PlaylistScreen from './screens/PlaylistScreen'
66
import SettingsScreen from './screens/SettingsScreen'
77
import SettingsStore from './stores/SettingsStore'
8+
import ThemeStore from './stores/ThemeStore'
89
import TrackStore from './stores/TrackStore'
910
import WebSocketStore from './stores/WebSocketStore'
1011

1112
const settingsStore = new SettingsStore()
13+
const themeStore = new ThemeStore()
1214
const trackStore = new TrackStore()
13-
const webSocketStore = new WebSocketStore(trackStore)
15+
const webSocketStore = new WebSocketStore(trackStore, themeStore)
1416

1517
setTheme({
1618
primaryColor: MKColor.Orange,
@@ -44,14 +46,14 @@ export default class App extends Component {
4446
renderScene={(route, navigator) => {
4547
switch (route.name) {
4648
case 'playlist': {
47-
return (<PlaylistScreen navigator={navigator} webSocketStore={webSocketStore} playlist={route.playlist} />)
49+
return (<PlaylistScreen navigator={navigator} webSocketStore={webSocketStore} playlist={route.playlist} themeStore={themeStore} />)
4850
}
4951
case 'settings': {
50-
return (<SettingsScreen navigator={navigator} settingsStore={settingsStore} />)
52+
return (<SettingsScreen navigator={navigator} settingsStore={settingsStore} themeStore={themeStore} />)
5153
}
5254
default:
5355
case 'remote': {
54-
return (<HomeScreen trackStore={trackStore} webSocketStore={webSocketStore} navigator={navigator} settingsStore={settingsStore} />)
56+
return (<HomeScreen trackStore={trackStore} webSocketStore={webSocketStore} navigator={navigator} settingsStore={settingsStore} themeStore={themeStore} />)
5557
}
5658
}
5759
}}

src/components/ControlBar.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ export default class ControlBar extends React.Component {
1919
onPrevPress: PropTypes.func,
2020
onNextPress: PropTypes.func,
2121
onRepeatPress: PropTypes.func,
22-
onShufflePress: PropTypes.func
22+
onShufflePress: PropTypes.func,
23+
24+
backgroundColor: PropTypes.string,
25+
foreColor: PropTypes.string,
26+
highlightColor: PropTypes.string
2327
}
2428

2529
static defaultProps = {
@@ -28,31 +32,31 @@ export default class ControlBar extends React.Component {
2832
}
2933

3034
render = () => {
31-
const { landscape, onPlayPress, onPrevPress, onNextPress, onRepeatPress, onShufflePress, isPlaying, isStopped, repeatMode, shuffleMode } = this.props
35+
const { landscape, onPlayPress, onPrevPress, onNextPress, onRepeatPress, onShufflePress, isPlaying, isStopped, repeatMode, shuffleMode, backgroundColor, foreColor, highlightColor } = this.props
3236

33-
let repeatColor = colors.GREY_DARK
34-
let shuffleColor = colors.GREY_DARK
37+
let repeatColor = foreColor
38+
let shuffleColor = foreColor
3539
if (repeatMode !== 'NO_REPEAT') {
36-
repeatColor = colors.ORANGE
40+
repeatColor = highlightColor
3741
}
3842
if (shuffleMode !== 'NO_SHUFFLE') {
39-
shuffleColor = colors.ORANGE
43+
shuffleColor = highlightColor
4044
}
4145
const repeatIcon = <IconMaterial name={repeatMode === 'SINGLE_REPEAT' ? 'repeat-one' : 'repeat'} size={landscape ? 20 : 26} color={repeatColor} />
42-
const prevIcon = <IconMaterial name={'skip-previous'} size={landscape ? 20 : 26} color={colors.GREY_DARK} />
43-
const nextIcon = <IconMaterial name={'skip-next'} size={landscape ? 20 : 26} color={colors.GREY_DARK} />
46+
const prevIcon = <IconMaterial name={'skip-previous'} size={landscape ? 20 : 26} color={foreColor} />
47+
const nextIcon = <IconMaterial name={'skip-next'} size={landscape ? 20 : 26} color={foreColor} />
4448
const shuffleIcon = <IconMaterial name={'shuffle'} size={landscape ? 20 : 26} color={shuffleColor} />
4549

4650
return (
47-
<View style={[theme.cardStyle, landscape ? styles.landscapeContainer : styles.container]}>
51+
<View style={[theme.cardStyle, landscape ? styles.landscapeContainer : styles.container, { backgroundColor, borderColor: backgroundColor, borderRadius: 0 }]}>
4852
<CircleButton onPress={onRepeatPress} size={landscape ? 32 : 42}>
4953
{repeatIcon}
5054
</CircleButton>
5155
<CircleButton onPress={onPrevPress} size={landscape ? 32 : 42}>
5256
{prevIcon}
5357
</CircleButton>
5458
<CircleButton onPress={onPlayPress} size={landscape ? 55 : 84}>
55-
<PlayPauseButton isPlaying={isPlaying} isStopped={isStopped} landscape={landscape} />
59+
<PlayPauseButton color={highlightColor} isPlaying={isPlaying} isStopped={isStopped} landscape={landscape} />
5660
</CircleButton>
5761
<CircleButton onPress={onNextPress} size={landscape ? 32 : 42}>
5862
{nextIcon}

src/components/PlayPauseButton.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,25 @@ import colors from '../theme/colors'
66

77
export default class PlayPauseButton extends React.Component {
88
static propTypes = {
9+
color: PropTypes.string,
910
isPlaying: PropTypes.bool,
1011
isStopped: PropTypes.bool,
1112
landscape: PropTypes.bool
1213
}
1314

1415
render () {
15-
const { isPlaying, isStopped, landscape } = this.props
16+
const { color, isPlaying, isStopped, landscape } = this.props
1617

1718
const playIcon = (
18-
<View style={[landscape ? styles.playPauseButtonLandscape : styles.playPauseButton, styles.playIcon]}>
19+
<View style={[landscape ? styles.playPauseButtonLandscape : styles.playPauseButton, { backgroundColor: color }]}>
1920
<Text>
2021
{' '}<IconEntypo name={'controller-play'} size={landscape ? 26 : 40} color={colors.WHITE} />
2122
</Text>
2223
</View>
2324
)
2425

2526
const pauseIcon = (
26-
<View style={[landscape ? styles.playPauseButtonLandscape : styles.playPauseButton, styles.pauseIcon]}>
27+
<View style={[landscape ? styles.playPauseButtonLandscape : styles.playPauseButton, { backgroundColor: color }]}>
2728
<IconEntypo name={'controller-paus'} size={landscape ? 26 : 40} color={colors.WHITE} />
2829
</View>
2930
)

src/components/PlaylistNavigation.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,23 @@ import colors from '../theme/colors'
44

55
export default class PlaylistNavigation extends Component {
66
static propTypes = {
7+
backgroundColor: PropTypes.string,
8+
foreColor: PropTypes.string,
79
playlistsDataStore: PropTypes.object,
810
navigate: PropTypes.func
911
}
1012

1113
render () {
12-
const { playlistsDataStore, navigate } = this.props
14+
const { playlistsDataStore, navigate, backgroundColor, foreColor } = this.props
1315

1416
return (
1517
<ListView
1618
dataSource={playlistsDataStore}
1719
enableEmptySections={true}
20+
style={{ backgroundColor }}
1821
renderHeader={() => (
1922
<View style={styles.listItem}>
20-
<Text style={{ fontWeight: 'bold', fontSize: 24 }}>Playlists</Text>
23+
<Text style={{ fontWeight: 'bold', fontSize: 24, color: foreColor }}>Playlists</Text>
2124
</View>
2225
)}
2326
renderRow={(playlist) => {
@@ -28,7 +31,7 @@ export default class PlaylistNavigation extends Component {
2831
>
2932
<View>
3033
<View style={styles.listItem}>
31-
<Text>{playlist.name}</Text>
34+
<Text style={{ color: foreColor }}>{playlist.name}</Text>
3235
</View>
3336
</View>
3437
</TouchableNativeFeedback>

src/components/ProgressSlider.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import metrics from '../theme/metrics'
88
@observer
99
export default class ProgressSlider extends React.Component {
1010
static propTypes = {
11+
highlightColor: PropTypes.string,
1112
min: PropTypes.number,
1213
max: PropTypes.number,
1314
value: PropTypes.number,
@@ -39,7 +40,7 @@ export default class ProgressSlider extends React.Component {
3940
}
4041

4142
render () {
42-
const { min, max } = this.props
43+
const { highlightColor, min, max } = this.props
4344
return (
4445
<CustomSlider
4546
ref={'slider'}
@@ -50,7 +51,7 @@ export default class ProgressSlider extends React.Component {
5051
onPress={this._handlePress}
5152
onConfirm={this._handleConfirm}
5253
upperTrackColor="rgba(0, 0, 0, 0)"
53-
lowerTrackColor={colors.ORANGE}
54+
lowerTrackColor={highlightColor}
5455
/>
5556
)
5657
}

src/components/Toolbar.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import colors from '../theme/colors'
55

66
export default class Toolbar extends Component {
77
static propTypes = {
8+
color: PropTypes.string,
89
drawerFunction: PropTypes.func,
910
navigator: PropTypes.object,
1011
title: PropTypes.string,
@@ -31,7 +32,7 @@ export default class Toolbar extends Component {
3132
}
3233

3334
render () {
34-
const { title, settingsMenu, showDrawer, drawerFunction } = this.props
35+
const { color, title, settingsMenu, showDrawer, drawerFunction } = this.props
3536
const actions = [
3637
{
3738
title: 'Settings'
@@ -42,7 +43,7 @@ export default class Toolbar extends Component {
4243
<Icon.ToolbarAndroid
4344
navIconName={showDrawer ? 'md-menu' : 'md-arrow-back'}
4445
onIconClicked={showDrawer ? drawerFunction : this._backButtonPressed}
45-
style={styles.toolbar}
46+
style={[styles.toolbar, { backgroundColor: color }]}
4647
titleColor={'white'}
4748
title={title}
4849
actions={(settingsMenu ? actions : null)}
@@ -54,7 +55,6 @@ export default class Toolbar extends Component {
5455

5556
const styles = StyleSheet.create({
5657
toolbar: {
57-
backgroundColor: colors.ORANGE,
5858
height: 56,
5959
elevation: 2
6060
}

src/screens/HomeScreen.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default class HomeScreen extends Component {
1818
navigator: PropTypes.object,
1919
settingsStore: PropTypes.object,
2020
trackStore: PropTypes.object,
21+
themeStore: PropTypes.object,
2122
webSocketStore: PropTypes.object
2223
}
2324

@@ -141,6 +142,7 @@ export default class HomeScreen extends Component {
141142
isStopped, currentTime, totalTime, repeatMode, shuffleMode } = this.props.trackStore
142143
const { playlistsDataStore, queueDataStore } = this.props.trackStore
143144
const { isConnected } = this.props.webSocketStore
145+
const { themeStore } = this.props
144146

145147
if (!isConnected) {
146148
title = 'Not Connected'
@@ -166,10 +168,14 @@ export default class HomeScreen extends Component {
166168
ref="drawer"
167169
drawerWidth={300}
168170
drawerPosition={DrawerLayoutAndroid.positions.Left}
169-
renderNavigationView={() => <PlaylistNavigation playlistsDataStore={playlistsDataStore} navigate={this._handlePlaylistNavigation} />}
171+
renderNavigationView={() =>
172+
<PlaylistNavigation
173+
backgroundColor={themeStore.backgroundColor()} foreColor={themeStore.foreColor()}
174+
playlistsDataStore={playlistsDataStore} navigate={this._handlePlaylistNavigation}
175+
/>}
170176
>
171-
<View style={styles.container}>
172-
<StatusBar animated hidden={this.state.bouncing} backgroundColor={colors.ORANGE_DARK} />
177+
<View style={[styles.container, { backgroundColor: this.props.themeStore.backgroundColor() }]}>
178+
<StatusBar animated hidden={this.state.bouncing} backgroundColor={this.props.themeStore.barColor()} />
173179
<View style={styles.content}>
174180
<View style={{ flex: 1, alignItems: 'center' }}>
175181
<TouchableWithoutFeedback onPress={this._imageTap}>
@@ -192,15 +198,16 @@ export default class HomeScreen extends Component {
192198
: null
193199
}
194200
<Animated.View style={[styles.toolbar, { transform: [{ translateY: this.state.bounceUpValue }] }]} >
195-
<Toolbar title={'Home'} navigator={this.props.navigator} settingsMenu showDrawer drawerFunction={() => { this.refs.drawer.openDrawer() }} />
201+
<Toolbar title={'Home'} color={themeStore.barColor()} navigator={this.props.navigator} settingsMenu showDrawer drawerFunction={() => { this.refs.drawer.openDrawer() }} />
196202
</Animated.View>
197203
<Animated.View style={[styles.toolbarSongInfo, { transform: [{ translateY: this.state.bounceUpValue }] }]} >
198204
<SongInfo title={title} artist={artist} album={album} onPress={this._handleSongInfoPress} />
199205
</Animated.View>
200206
<Animated.View style={[styles.controlBar, { transform: [{ translateY: this.state.bounceDownValue }] }]} >
201207
<ControlBar
208+
backgroundColor={themeStore.backgroundColor()} foreColor={themeStore.foreColor()} highlightColor={themeStore.highlightColor()}
202209
isPlaying={isPlaying} isStopped={isStopped} landscape={this.state.orientation === 'LANDSCAPE'}
203-
repeatMode={repeatMode} shuffleMode={shuffleMode}
210+
repeatMode={repeatMode} shuffleMode={shuffleMode} themeStore={this.props.themeStore}
204211
onPlayPress={this._handlePlayPress} onPrevPress={this._handlePrevPress} onNextPress={this._handleNextPress}
205212
onShufflePress={this._handleShufflePress} onRepeatPress={this._handleRepeatPress}
206213
/>
@@ -212,7 +219,7 @@ export default class HomeScreen extends Component {
212219
}]}
213220
>
214221
<ProgressSlider
215-
ref={'progressSlider'} min={0} max={totalTime}
222+
ref={'progressSlider'} min={0} max={totalTime} highlightColor={themeStore.highlightColor()}
216223
value={currentTime} onValueChange={this._handleProgressBarTouch}
217224
/>
218225
</Animated.View>

src/screens/PlaylistScreen.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default class PlaylistScreen extends Component {
1010
static propTypes = {
1111
navigator: PropTypes.object,
1212
playlist: PropTypes.object,
13+
themeStore: PropTypes.object,
1314
webSocketStore: PropTypes.object
1415
}
1516

@@ -28,7 +29,7 @@ export default class PlaylistScreen extends Component {
2829
}
2930

3031
render () {
31-
const { playlist } = this.props
32+
const { playlist, themeStore } = this.props
3233
let ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => JSON.stringify(r1) !== JSON.stringify(r2) })
3334
const cleanTracks = []
3435
for (let i = 0; i < playlist.tracks.length; i++) {
@@ -47,11 +48,11 @@ export default class PlaylistScreen extends Component {
4748
ds = ds.cloneWithRows(cleanTracks)
4849

4950
return (
50-
<View style={styles.container}>
51-
<StatusBar animated backgroundColor={colors.ORANGE_DARK} />
52-
<Toolbar title={playlist.name} navigator={this.props.navigator} />
53-
<View style={styles.content}>
54-
<SongList black data={ds} handlePress={this._handlePress} />
51+
<View style={[styles.container]}>
52+
<StatusBar animated backgroundColor={themeStore.barColor()} />
53+
<Toolbar title={playlist.name} navigator={this.props.navigator} color={themeStore.barColor()} />
54+
<View style={[styles.content, { backgroundColor: themeStore.backgroundColor() }]}>
55+
<SongList black={!(themeStore.themeEnabled && themeStore.themeType === 'FULL')} data={ds} handlePress={this._handlePress} />
5556
</View>
5657
</View>
5758
)
@@ -64,8 +65,7 @@ const styles = StyleSheet.create({
6465
alignSelf: 'stretch'
6566
},
6667
content: {
67-
flex: 1,
68-
backgroundColor: colors.GREY_LIGHTER
68+
flex: 1
6969
},
7070
controlBar: {
7171
flex: 0,

src/screens/SettingsScreen.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,29 @@ const theme = getTheme()
1212
export default class SettingsScreen extends Component {
1313
static propTypes = {
1414
navigator: PropTypes.object,
15-
settingsStore: PropTypes.object
15+
settingsStore: PropTypes.object,
16+
themeStore: PropTypes.object
1617
}
1718

1819
_ipChanged = (newIP) => {
1920
this.props.settingsStore.updateIPAddress(newIP)
2021
}
2122

2223
render () {
24+
const { themeStore } = this.props
2325
return (
24-
<View style={styles.container}>
25-
<StatusBar animated backgroundColor={colors.ORANGE_DARK} />
26-
<Toolbar title={'Settings'} navigator={this.props.navigator} />
26+
<View style={[styles.container, { backgroundColor: themeStore.backgroundColor() }]}>
27+
<StatusBar animated backgroundColor={themeStore.barColor()} />
28+
<Toolbar title={'Settings'} navigator={this.props.navigator} color={themeStore.barColor()} />
2729
<View style={styles.content}>
2830
<View style={styles.settingsContent}>
29-
<Text>GPMDP IP Address</Text>
31+
<Text style={{ color: themeStore.foreColor() }}>GPMDP IP Address</Text>
3032
<TextInput
33+
style={{ color: themeStore.foreColor() }}
3134
autoCorrect={false}
3235
defaultValue={this.props.settingsStore.IP_ADDRESS === 'NOT_SET' ? '' : this.props.settingsStore.IP_ADDRESS}
3336
keyboardType="numeric"
34-
underlineColorAndroid={colors.ORANGE_DARK}
37+
underlineColorAndroid={themeStore.highlightColor()}
3538
placeholder="GPMDP IP Address"
3639
onChangeText={this._ipChanged}
3740
/>
@@ -48,8 +51,7 @@ const styles = StyleSheet.create({
4851
alignSelf: 'stretch'
4952
},
5053
content: {
51-
flex: 1,
52-
backgroundColor: colors.GREY_LIGHTER
54+
flex: 1
5355
},
5456
controlBar: {
5557
flex: 0,

0 commit comments

Comments
 (0)