Skip to content

Commit 2146c96

Browse files
committed
refactor lists to shared helper
1 parent 64f4080 commit 2146c96

File tree

16 files changed

+534
-172
lines changed

16 files changed

+534
-172
lines changed

App/Actions/FollowActions.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
var Dispatcher = require('../Dispatcher');
2+
var AppConstants = require('../Constants/AppConstants');
3+
var FollowService = require('../Api/FollowService');
4+
5+
var FollowActions = {
6+
7+
fetchList: function(username, callback) {
8+
FollowService.fetchList(username, function(error, listProps) {
9+
if(callback) callback(error);
10+
11+
if (!error) {
12+
Dispatcher.dispatch({
13+
actionType: AppConstants.FOLLOW_LIST_UPDATED,
14+
listProps: listProps
15+
});
16+
}
17+
});
18+
}
19+
};
20+
21+
module.exports = FollowActions;

App/Api/FollowService.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
var client = require('../Api/HTTPClient')
2+
3+
var FolllowService = {
4+
parseFolllow: function(response) {
5+
if (!response) return null;
6+
7+
return {
8+
id: response.id,
9+
username: response.username
10+
};
11+
},
12+
13+
parseFolllows: function(response) {
14+
if (!response) return null;
15+
16+
var out = {follows: []};
17+
for(var i in response.follows) {
18+
out.follows.push(FolllowService.parseFolllow(response.follows[i]));
19+
}
20+
out.username = response.username;
21+
return out;
22+
},
23+
24+
fetchList: function(username, callback) {
25+
client.get("api/follows/" + username, {}, function(error, response) {
26+
var listProps = FolllowService.parseFolllows(response);
27+
callback(error, listProps);
28+
});
29+
}
30+
};
31+
32+
module.exports = FolllowService;

App/Components/SegmentedControl.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// https://github.com/ide/react-native-button
2+
3+
var React = require('react-native');
4+
var {
5+
StyleSheet,
6+
TouchableHighlight,
7+
View
8+
} = React;
9+
10+
var cssVar = require('../Lib/cssVar');
11+
var Text = require('../Components/Text');
12+
var AppActions = require('../Actions/AppActions');
13+
14+
var SegmentedControl = React.createClass({
15+
segmentComponents: function() {
16+
var out = [];
17+
for(var i = 0; i < this.props.items.length; i++) {
18+
var item = this.props.items[i];
19+
out.push(
20+
<Segment {...item} key={"item" + i} currentRoute={this.props.currentRoute} />
21+
);
22+
};
23+
return out;
24+
},
25+
26+
render: function() {
27+
return (
28+
<View style={styles.container}>
29+
<View style={styles.control}>
30+
{this.segmentComponents()}
31+
</View>
32+
</View>
33+
);
34+
}
35+
});
36+
37+
var Segment = React.createClass({
38+
onSelection: function() {
39+
AppActions.launchRelativeItem(this.props.currentRoute, this.props);
40+
},
41+
42+
render: function() {
43+
if (this.props.selected) {
44+
return (
45+
<View
46+
style={styles.flex}
47+
>
48+
<View style={[styles.button, styles.selectedButton]}>
49+
<Text style={[styles.text, styles.selectedText]}>
50+
{this.props.title}
51+
</Text>
52+
</View>
53+
</View>
54+
);
55+
}
56+
else {
57+
return (
58+
<TouchableHighlight
59+
style={styles.flex}
60+
underlayColor='#FFFFFF'
61+
onPress={this.onSelection}
62+
>
63+
<View style={[styles.button, styles.linkButton]}>
64+
<Text style={[styles.text, styles.linkText]}>
65+
{this.props.title}
66+
</Text>
67+
</View>
68+
</TouchableHighlight>
69+
);
70+
}
71+
}
72+
});
73+
74+
75+
var styles = StyleSheet.create({
76+
container: {
77+
backgroundColor: cssVar('blue50'),
78+
padding: 10
79+
},
80+
control: {
81+
flex: 1,
82+
flexDirection: 'row',
83+
borderColor: 'white',
84+
borderWidth: 1,
85+
borderRadius: 4
86+
},
87+
flex: {
88+
flex: 1
89+
},
90+
button: {
91+
padding: 5,
92+
flex: 1,
93+
justifyContent: 'center',
94+
alignItems: 'center',
95+
},
96+
selectedButton: {
97+
backgroundColor: 'white',
98+
},
99+
linkButton: {
100+
backgroundColor: cssVar('blue50'),
101+
},
102+
text: {
103+
fontSize: 16
104+
},
105+
selectedText: {
106+
color: cssVar('blue50'),
107+
},
108+
linkText: {
109+
color: 'white'
110+
}
111+
});
112+
113+
module.exports = SegmentedControl;

App/Components/SimpleList.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ var {
33
ListView
44
} = React;
55

6+
var RefreshableListView = require('react-native-refreshable-listview');
7+
68
var SimpleListItem = require('../Components/SimpleListItem');
79

810
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
@@ -13,17 +15,26 @@ var SimpleList = React.createClass({
1315
if (this.props.currentRoute) passAlong.currentRoute = this.props.currentRoute;
1416
if (this.props.navigator) passAlong.navigator = this.props.navigator;
1517
if (this.props.nextIcon) passAlong.nextIcon = this.props.nextIcon;
18+
if (this.props.noTap) passAlong.noTap = this.props.noTap;
19+
20+
if (this.props.getItemProps) {
21+
// swtich it out
22+
item = this.props.getItemProps(item);
23+
}
24+
1625
return (
17-
<SimpleListItem {...passAlong} {...item} key={"item" + rowId} />
26+
<SimpleListItem {...passAlong} {...item} key={"item" + (item.key || rowId)} />
1827
);
1928
},
2029

2130
render: function() {
31+
var Component = this.props.reloadList ? RefreshableListView : ListView;
2232
return (
23-
<ListView
33+
<Component
2434
automaticallyAdjustContentInsets={false}
2535
dataSource={ds.cloneWithRows(this.props.items)}
2636
renderRow={this.renderRow}
37+
loadData={this.props.reloadList}
2738
/>
2839
);
2940
}

App/Constants/AppConstants.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ module.exports = keyMirror({
1010
NETWORK_ACTIVITY: null,
1111
NAVBAR_UPDATE: null,
1212
POST_LIST_UPDATED: null,
13-
POST_ADDED: null
13+
POST_ADDED: null,
14+
FOLLOW_LIST_UPDATED: null
1415
});

App/Mixins/ListHelper.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// helper to handle showing lists of things
2+
// parent must implement methods
3+
// required: getListItem, getItemProps
4+
// optional: isListChange, reloadList
5+
//
6+
// and give props
7+
// required: store, currentRoute
8+
// optional: listProps, segment
9+
10+
var React = require('react-native');
11+
var {
12+
View,
13+
StyleSheet,
14+
ListView
15+
} = React;
16+
17+
var NavigationListener = require('../Mixins/NavigationListener');
18+
19+
var Loading = require('../Screens/Loading');
20+
var Text = require('../Components/Text');
21+
var SegmentedControl = require('../Components/SegmentedControl');
22+
var SimpleList = require('../Components/SimpleList');
23+
24+
var ListHelper = {
25+
mixins: [NavigationListener],
26+
27+
getInitialState: function() {
28+
return this.getListState();
29+
},
30+
31+
getListState: function() {
32+
return {
33+
items: this.getListItems()
34+
};
35+
},
36+
37+
onListChange: function(arg) {
38+
if (!this.isListChange || this.isListChange(arg)) {
39+
this.setState(this.getListState());
40+
}
41+
},
42+
43+
onDidFocusNavigation: function() {
44+
// items may have changed
45+
this.setState(this.getListState());
46+
},
47+
48+
componentDidMount: function() {
49+
this.props.store.addChangeListener(this.onListChange);
50+
if (this.reloadList) {
51+
this.reloadList();
52+
}
53+
},
54+
55+
componentWillUnmount: function() {
56+
this.props.store.removeChangeListener(this.onListChange);
57+
},
58+
59+
renderItems: function() {
60+
return (
61+
<SimpleList
62+
{...this.props.listProps}
63+
style={styles.flex}
64+
getItemProps={this.getItemProps}
65+
items={this.state.items}
66+
reloadList={this.reloadList}
67+
/>
68+
);
69+
},
70+
71+
renderEmpty: function() {
72+
return(
73+
<Text>
74+
No Items
75+
</Text>
76+
);
77+
},
78+
79+
renderHeader: function() {
80+
if (!this.props.segment) return null;
81+
return (
82+
<SegmentedControl currentRoute={this.props.currentRoute} {...this.props.segment} />
83+
);
84+
},
85+
86+
renderContent: function() {
87+
var header = this.renderHeader();
88+
var content;
89+
if (this.state.items.length === 0) {
90+
content = this.renderEmpty();
91+
}
92+
else {
93+
content = this.renderItems();
94+
}
95+
96+
return (
97+
<View style={styles.flex}>
98+
{header}
99+
{content}
100+
</View>
101+
);
102+
},
103+
104+
render: function() {
105+
if (!this.state.items) {
106+
// TODO: load error?
107+
return <Loading />;
108+
}
109+
else {
110+
return this.renderContent();
111+
}
112+
}
113+
};
114+
115+
var styles = StyleSheet.create({
116+
flex: {
117+
flex: 1
118+
}
119+
});
120+
121+
module.exports = ListHelper;

App/Models/Follow.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
var assign = require('../Lib/assignDefined');
2+
3+
var Model = function(options) {
4+
this.data = {};
5+
this.setAttributes(options);
6+
};
7+
8+
Model.prototype.setAttributes = function(options) {
9+
options = (options || {});
10+
assign(this.data, {
11+
id: options.id,
12+
username: options.username
13+
});
14+
};
15+
16+
module.exports = Model;

App/Models/Post.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Model.prototype.setAttributes = function(options) {
99
options = (options || {});
1010
assign(this.data, {
1111
id: options.id,
12-
content: options.content
12+
content: options.content,
13+
username: options.username
1314
});
1415
};
1516

App/Navigation/Router.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,21 @@ var LoggedIn = {
3939
switch (host) {
4040
case 'dashboard':
4141
var dashboard = Routes.Dashboard();
42+
dashboard._routerAppend = 'posts';
4243
dashboard.parse = function(path) {
4344
switch(path) {
4445
case 'settings':
4546
return Routes.Settings();
4647
case 'post':
4748
return Routes.CreatePost();
49+
case 'posts':
50+
var posts = Routes.PostList('bleonard');
51+
posts._routerReplace = true;
52+
return posts;
53+
case 'follows':
54+
var follows = Routes.FollowList('bleonard');
55+
follows._routerReplace = true;
56+
return follows;
4857
default:
4958
return null;
5059
};
@@ -84,6 +93,7 @@ var Router = {
8493
var parsed = parseUri(toParse);
8594
var pieces = parsed.path.split("/");
8695
pieces.unshift(parsed.host);
96+
pieces = pieces.filter(function(v) { return v && v.length > 0 });
8797
var current = loggedIn ? LoggedIn : LoggedOut;
8898
var stack = [];
8999

0 commit comments

Comments
 (0)