|
5 | 5 |
|
6 | 6 | **🔗 Quick Links**
|
7 | 7 |
|
8 |
| -- [Register](https://getstream.io/activity-feeds/trial/) to get an API key for Stream Activity Feeds |
| 8 | +- [Register](https://getstream.io/activity-feed/sdk/flutter/tutorial/) to get an API key for Stream Activity Feeds |
9 | 9 | - [Stream Activity Feeds UI Kit](https://getstream.io/activity-feeds/ui-kit/)
|
10 | 10 |
|
11 |
| -### Changelog |
| 11 | +## 🛠 Installation |
12 | 12 |
|
13 |
| -Check out the [changelog on pub.dev](https://pub.dev/packages/stream_feed/changelog) to see the latest changes in the package. |
| 13 | +#### Install from pub <a href="https://pub.dartlang.org/packages/stream_feed"><img alt="Pub" src="https://img.shields.io/pub/v/stream_feed.svg"></a> |
14 | 14 |
|
15 |
| -## Getting started |
16 |
| - |
17 |
| -### Add dependency |
18 |
| -Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_feed) |
| 15 | +Next step is to add `stream_feed` to your dependencies, to do that just open pubspec.yaml and add it inside the dependencies section. |
19 | 16 |
|
20 | 17 | ```yaml
|
21 | 18 | dependencies:
|
22 |
| - stream_feed: ^latest-version |
| 19 | + flutter: |
| 20 | + sdk: flutter |
| 21 | + |
| 22 | + stream_feed: ^[latest-version] |
23 | 23 | ```
|
| 24 | +#### Using with Flutter |
24 | 25 |
|
25 |
| -You should then run `flutter packages get` |
| 26 | +This package can be integrated into Flutter applications. Remember to not expose the App Secret in your Flutter web apps, mobile apps, or other non-trusted environments like desktop apps. |
26 | 27 |
|
27 |
| -## 🔮 Example Project |
| 28 | +## 🔌 Usage |
| 29 | +
|
| 30 | +### API client setup Serverside + Clientside |
| 31 | +
|
| 32 | +If you want to use the API client directly on your web/mobile app you need to generate a user token server-side and pass it. |
| 33 | +
|
| 34 | +#### Server-side token generation |
| 35 | +
|
| 36 | +```dart |
| 37 | + |
| 38 | +// Instantiate a new client (server side) |
| 39 | +const apiKey = 'my-API-key'; |
| 40 | +const secret = 'my-API-secret'; |
28 | 41 |
|
29 |
| -There is a detailed Flutter example project in the `example` folder. You can directly run and play on it. |
| 42 | +// Instantiate a new client (server side) |
| 43 | +var client = StreamFeedClient.connect(apiKey, secret: secret); |
30 | 44 |
|
31 |
| -## 🛠 Setup API Client |
| 45 | +// Optionally supply the app identifier and an options object specifying the data center to use and timeout for requests (15s) |
| 46 | +client = StreamFeedClient.connect(apiKey, |
| 47 | + secret: secret, |
| 48 | + appId: 'yourappid', |
| 49 | + options: StreamHttpClientOptions( |
| 50 | + location: Location.usEast, connectTimeout: Duration(seconds: 15))); |
| 51 | + |
| 52 | +// Create a token for user with id "the-user-id" |
| 53 | +final userToken = client.frontendToken('the-user-id'); |
| 54 | +``` |
32 | 55 |
|
33 |
| -First you need to instantiate a feed client. The Feed client will manage API calls. You should only create the client once and re-use it across your application. |
| 56 | +> :warning: for security, you must never expose your API secret or generated client side token, and it's highly recommended to use `exp` claim in client side token. |
| 57 | +
|
| 58 | + |
| 59 | +#### Client API init |
34 | 60 |
|
35 | 61 | ```dart
|
36 |
| -final client = StreamFeedClient.connect("stream-feed-api-key",token:userToken); |
| 62 | +// Instantiate new client with a user token |
| 63 | +var client = StreamFeedClient.connect(apiKey, token: Token('userToken')); |
37 | 64 | ```
|
| 65 | + |
| 66 | +### 🔮 Examples |
| 67 | + |
| 68 | +```dart |
| 69 | +// Instantiate a feed object server side |
| 70 | +var user1 = client.flatFeed('user', '1'); |
| 71 | +
|
| 72 | +// Get activities from 5 to 10 (slow pagination) |
| 73 | +final activities = await user1.getActivities(limit: 5, offset: 5); |
| 74 | +// Filter on an id less than a given UUID |
| 75 | +final filtered_activities = await user1.getActivities( |
| 76 | + limit: 5, |
| 77 | + filter: Filter().idLessThan('e561de8f-00f1-11e4-b400-0cc47a024be0') |
| 78 | +
|
| 79 | +// All API calls are performed asynchronous and return a Promise object |
| 80 | +await user1 |
| 81 | + .getActivities( |
| 82 | + limit: 5, |
| 83 | + filter: Filter().idLessThan('e561de8f-00f1-11e4-b400-0cc47a024be0')) |
| 84 | + .then((value) => /* on success */ |
| 85 | + print(value)) |
| 86 | + .onError((error, |
| 87 | + stackTrace) => /* on failure, reason.error contains an explanation */ |
| 88 | + print(error)); |
| 89 | +
|
| 90 | +// Create a new activity |
| 91 | +final activity = Activity( actor: '1', verb: 'tweet', object: '1', foreignId: 'tweet:1' ); |
| 92 | +final added_activity = await user1.addActivity(activity); |
| 93 | +// Create a bit more complex activity |
| 94 | +final complex_activity = Activity( |
| 95 | + actor: '1', |
| 96 | + verb: 'run', |
| 97 | + object: '1', |
| 98 | + foreignId: 'run:1', |
| 99 | + extraData: { |
| 100 | + 'course': {'name': 'Golden Gate park', 'distance': 10}, |
| 101 | + 'participants': ['Thierry', 'Tommaso'], |
| 102 | + 'started_at': DateTime.now().toIso8601String(), |
| 103 | + }, |
| 104 | + ); |
| 105 | +final added_complex_activity = await user1.addActivity(complex_activity); |
| 106 | +
|
| 107 | +// Remove an activity by its id |
| 108 | +await user1.removeActivityById('e561de8f-00f1-11e4-b400-0cc47a024be0'); |
| 109 | +// or remove by the foreign id |
| 110 | +await user1.removeActivityByForeignId('tweet:1'); |
| 111 | +
|
| 112 | +// mark a notification feed as read |
| 113 | +await notification1.getActivities( |
| 114 | + marker: ActivityMarker().allRead(), |
| 115 | +); |
| 116 | +
|
| 117 | +
|
| 118 | +// mark a notification feed as seen |
| 119 | +await notification1.getActivities( |
| 120 | + marker: ActivityMarker().allSeen(), |
| 121 | +); |
| 122 | +
|
| 123 | +// Follow another feed |
| 124 | +await user1.follow(client.flatFeed('flat', '42')); |
| 125 | +
|
| 126 | +// Stop following another feed |
| 127 | +await user1.unfollow(client.flatFeed('flat', '42')); |
| 128 | +
|
| 129 | +// Stop following another feed while keeping previously published activities |
| 130 | +// from that feed |
| 131 | +await user1.unfollow(client.flatFeed('flat', '42'), keepHistory: true); |
| 132 | +
|
| 133 | +// Follow another feed without copying the history |
| 134 | +await user1.follow(client.flatFeed('flat', '42'), activityCopyLimit: 0); |
| 135 | +
|
| 136 | +// List followers, following |
| 137 | +await user1.getFollowers(limit: 10, offset: 10); |
| 138 | +await user1.getFollowed(limit: 10, offset: 0); |
| 139 | +
|
| 140 | +
|
| 141 | +await user1.follow(client.flatFeed('flat', '42')); |
| 142 | +
|
| 143 | +// adding multiple activities |
| 144 | +const activities = [ |
| 145 | + Activity(actor: '1', verb: 'tweet', object: '1'), |
| 146 | + Activity(actor: '2', verb: 'tweet', object: '3'), |
| 147 | +]; |
| 148 | +await user1.addActivities(activities); |
| 149 | +
|
| 150 | +// specifying additional feeds to push the activity to using the to param |
| 151 | +// especially useful for notification style feeds |
| 152 | +final to = FeedId.fromIds(['user:2', 'user:3']); |
| 153 | +final activityTo = Activity( |
| 154 | + to: to, |
| 155 | + actor: '1', |
| 156 | + verb: 'tweet', |
| 157 | + object: '1', |
| 158 | + foreignId: 'tweet:1', |
| 159 | +); |
| 160 | +await user1.addActivity(activityTo); |
| 161 | +
|
| 162 | +
|
| 163 | +// adding one activity to multiple feeds |
| 164 | +final feeds = FeedId.fromIds(['flat:1', 'flat:2', 'flat:3', 'flat:4']); |
| 165 | +final activityTarget = Activity( |
| 166 | + actor: 'User:2', |
| 167 | + verb: 'pin', |
| 168 | + object: 'Place:42', |
| 169 | + target: 'Board:1', |
| 170 | +); |
| 171 | +
|
| 172 | +// ⚠️ server-side only! |
| 173 | +await client.batch.addToMany(activityTarget, feeds!); |
| 174 | +
|
| 175 | +// Batch create follow relations (let flat:1 follow user:1, user:2 and user:3 feeds in one single request) |
| 176 | +const follows = [ |
| 177 | + Follow('flat:1', 'user:1'), |
| 178 | + Follow('flat:1', 'user:2'), |
| 179 | + Follow('flat:1', 'user:3'), |
| 180 | +]; |
| 181 | +
|
| 182 | +// ⚠️ server-side only! |
| 183 | +await client.batch.followMany(follows); |
| 184 | +
|
| 185 | +// Updating parts of an activity |
| 186 | +final set = { |
| 187 | + 'product.price': 19.99, |
| 188 | + shares: { |
| 189 | + facebook: '...', |
| 190 | + twitter: '...', |
| 191 | + }, |
| 192 | +}; |
| 193 | +final unset = ['daily_likes', 'popularity']; |
| 194 | +
|
| 195 | +// ...by ID |
| 196 | +final update = ActivityUpdate.withId( '54a60c1e-4ee3-494b-a1e3-50c06acb5ed4', set, unset); |
| 197 | +await client.updateActivityById(update); |
| 198 | +// ...or by combination of foreign ID and time |
| 199 | +const timestamp = DateTime.now(); |
| 200 | +const foreignID= 'product:123'; |
| 201 | +final update2 = ActivityUpdate.withForeignId( |
| 202 | + foreignID, |
| 203 | + timestamp, |
| 204 | + set, |
| 205 | + unset, |
| 206 | +); |
| 207 | +await client.updateActivityById(update2); |
| 208 | +
|
| 209 | +
|
| 210 | +// update the 'to' fields on an existing activity |
| 211 | +// client.flatFeed("user", "ken").function (foreign_id, timestamp, new_targets, added_targets, removed_targets) |
| 212 | +// new_targets, added_targets, and removed_targets are all arrays of feed IDs |
| 213 | +// either provide only the `new_targets` parameter (will replace all targets on the activity), |
| 214 | +// OR provide the added_targets and removed_targets parameters |
| 215 | +// NOTE - the updateActivityToTargets method is not intended to be used in a browser environment. |
| 216 | +await client.flatFeed('user', 'ken').updateActivityToTargets('foreign_id:1234', timestamp, ['feed:1234']); |
| 217 | +await client.flatFeed('user', 'ken').updateActivityToTargets('foreign_id:1234', timestamp, null, ['feed:1234']); |
| 218 | +await client.flatFeed('user', 'ken').updateActivityToTargets('foreign_id:1234', timestamp, null, null, ['feed:1234']); |
| 219 | +``` |
| 220 | + |
| 221 | +### Realtime (Faye) |
| 222 | + |
| 223 | +Stream uses [Faye](http://faye.jcoglan.com) for realtime notifications. Below is quick guide to subscribing to feed changes |
| 224 | + |
| 225 | +```dart |
| 226 | +
|
| 227 | +// ⚠️ userToken is generated server-side (see previous section) |
| 228 | +final client = StreamFeedClient.connect('YOUR_API_KEY', token: userToken,appId: 'APP_ID'); |
| 229 | +final user1 = client.flatFeed('user', '1'); |
| 230 | +
|
| 231 | +// subscribe to the changes |
| 232 | +final subscription = await userFeed.subscribe((message) => print(message)); |
| 233 | +// now whenever something changes to the feed user 1 |
| 234 | +// the callback will be called |
| 235 | +
|
| 236 | +// To cancel a subscription you can call cancel on the |
| 237 | +// object returned from a subscribe call. |
| 238 | +// This will remove the listener from this channel. |
| 239 | +await subscription.cancel(); |
| 240 | +``` |
| 241 | + |
| 242 | +Docs are available on [GetStream.io](http://getstream.io/docs/?language=dart). |
| 243 | + |
| 244 | +## 🔮 Example Project |
| 245 | + |
| 246 | +There is a detailed Flutter example project in the [example](https://github.com/GetStream/stream-feed-flutter/blob/master/packages/stream_feed/example/main.dart) folder. You can directly run and play on it. |
| 247 | + |
38 | 248 | ## Contributing
|
39 | 249 |
|
40 | 250 | ### Code conventions
|
|
0 commit comments