Appearance
State Layer
About 1318 wordsAbout 4 min
Swift SDK - Feeds API
Table of Contents
- FeedState - Getting Started
- FeedState - Observing Activities
- FeedState - Observing Followers
- FeedState - Observing Members
- FeedState - Pagination
- ActivityState - Getting Started
- ActivityState - Observing Comments
- ActivityState - Observing Poll
- Paginated Lists - FeedList
- Paginated Lists - ActivityList
- Paginated Lists - BookmarkList
- Real-time Updates
FeedState - Getting Started
Access reactive, observable state for a feed using the .state property. FeedState is an ObservableObject that publishes changes to activities, followers, members, and notification status. Use it to drive SwiftUI views that automatically update when feed data changes.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct FeedView: View {
@StateObject var feedState: FeedState
init(client: FeedsClient) {
let feed = client.feed(for: FeedId(group: "user", id: "john"))
_feedState = StateObject(wrappedValue: feed.state)
}
var body: some View {
List(feedState.activities, id: \.id) { activity in
Text(activity.type)
}
.task {
// Load initial data
let feed = feedState.feed
try? await feed.getOrCreate()
}
}
}FeedState - Observing Activities
Observe the list of activities in a feed. The activities property on FeedState is a published array that updates automatically when activities are added, removed, or modified.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct ActivityListView: View {
@ObservedObject var feedState: FeedState
var body: some View {
VStack {
Text("Activities: \(feedState.activities.count)")
List(feedState.activities, id: \.id) { activity in
VStack(alignment: .leading) {
Text(activity.type)
.font(.headline)
Text("By: \(activity.actor)")
.font(.subheadline)
}
}
}
}
}
// Usage
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feed = client.feed(for: FeedId(group: "user", id: "john"))
try await feed.getOrCreate()
// feed.state.activities is now populated and observableFeedState - Observing Followers
Observe the followers of a feed. The followers property on FeedState provides a reactive list of users following this feed.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct FollowersView: View {
@ObservedObject var feedState: FeedState
var body: some View {
VStack {
Text("Followers: \(feedState.followers.count)")
List(feedState.followers, id: \.feedId) { follow in
HStack {
Text(follow.feedId)
Spacer()
Text(follow.targetFeedId)
.foregroundColor(.secondary)
}
}
}
}
}
// Load followers
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feed = client.feed(for: FeedId(group: "user", id: "john"))
try await feed.queryFollows(filter: .init(type: .followers))
// feed.state.followers is now populatedFeedState - Observing Members
Observe the members of a feed. The members property on FeedState provides a reactive list of feed members, useful for group or collaborative feeds.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct MembersView: View {
@ObservedObject var feedState: FeedState
var body: some View {
VStack {
Text("Members: \(feedState.members.count)")
List(feedState.members, id: \.userId) { member in
HStack {
Text(member.userId)
Spacer()
Text(member.role ?? "member")
.foregroundColor(.secondary)
}
}
}
}
}
// Load members
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feed = client.feed(for: FeedId(group: "team", id: "engineering"))
try await feed.queryFeedMembers()
// feed.state.members is now populatedFeedState - Pagination
Load more activities using pagination. Call queryMoreActivities(limit:) to fetch the next page of results. The state's activities array is automatically appended with new data.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct PaginatedFeedView: View {
@ObservedObject var feedState: FeedState
let feed: Feed
var body: some View {
List {
ForEach(feedState.activities, id: \.id) { activity in
Text(activity.type)
}
// Load more button at the bottom
Button("Load More") {
Task {
try await feed.queryMoreActivities(limit: 25)
}
}
}
.task {
// Initial load
try? await feed.getOrCreate()
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feed = client.feed(for: FeedId(group: "user", id: "john"))ActivityState - Getting Started
Access reactive state for a single activity using the .state property. ActivityState is an ObservableObject that publishes changes to the activity's data, comments, and poll state.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct ActivityDetailView: View {
@StateObject var activityState: ActivityState
init(client: FeedsClient, activityId: String) {
let activity = client.activity(
activityId: activityId,
feedId: FeedId(group: "user", id: "john")
)
_activityState = StateObject(wrappedValue: activity.state)
}
var body: some View {
VStack(alignment: .leading) {
if let activity = activityState.activity {
Text(activity.type)
.font(.headline)
Text("By: \(activity.actor)")
.font(.subheadline)
}
}
}
}ActivityState - Observing Comments
Observe the comments on an activity. The comments property on ActivityState provides a reactive list of comments that updates automatically.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct CommentsView: View {
@ObservedObject var activityState: ActivityState
let activity: Activity
var body: some View {
VStack {
Text("Comments: \(activityState.comments.count)")
List(activityState.comments, id: \.id) { comment in
VStack(alignment: .leading) {
Text(comment.text ?? "")
Text(comment.userId)
.font(.caption)
.foregroundColor(.secondary)
}
}
}
.task {
try? await activity.queryComments()
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let activity = client.activity(
activityId: "<activity_id>",
feedId: FeedId(group: "user", id: "john")
)ActivityState - Observing Poll
Observe the poll state attached to an activity. The poll property on ActivityState provides reactive access to poll data, including votes and options.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct PollView: View {
@ObservedObject var activityState: ActivityState
var body: some View {
if let poll = activityState.poll {
VStack(alignment: .leading) {
Text(poll.name ?? "Poll")
.font(.headline)
ForEach(poll.options, id: \.id) { option in
HStack {
Text(option.text)
Spacer()
Text("\(option.voteCount ?? 0) votes")
.foregroundColor(.secondary)
}
}
}
} else {
Text("No poll attached")
.foregroundColor(.secondary)
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let activity = client.activity(
activityId: "<activity_id>",
feedId: FeedId(group: "user", id: "john")
)
// activity.state.poll is now observablePaginated Lists - FeedList
Use FeedList to manage a paginated, observable list of feeds. This is useful when querying multiple feeds and displaying them in a SwiftUI view with built-in pagination support.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct FeedListView: View {
@ObservedObject var feedList: FeedList
var body: some View {
List {
ForEach(feedList.items, id: \.id) { feed in
Text(feed.id)
}
if feedList.hasMore {
ProgressView()
.task {
try? await feedList.loadMore()
}
}
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feedList = try await client.queryFeeds(
request: .init(filterConditions: [:])
)Paginated Lists - ActivityList
Use ActivityList to manage a paginated, observable list of activities across feeds. This provides automatic pagination and observable updates for activity queries.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct ActivityListPaginatedView: View {
@ObservedObject var activityList: ActivityList
var body: some View {
List {
ForEach(activityList.items, id: \.id) { activity in
VStack(alignment: .leading) {
Text(activity.type)
.font(.headline)
Text("By: \(activity.actor)")
.font(.subheadline)
}
}
if activityList.hasMore {
Button("Load More") {
Task {
try? await activityList.loadMore()
}
}
}
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let activityList = try await client.queryActivities(
request: .init(filterConditions: [:])
)Paginated Lists - BookmarkList
Use BookmarkList to manage a paginated, observable list of bookmarked activities. This provides automatic pagination and observable updates for bookmark queries.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct BookmarkListView: View {
@ObservedObject var bookmarkList: BookmarkList
var body: some View {
List {
ForEach(bookmarkList.items, id: \.id) { bookmark in
VStack(alignment: .leading) {
Text(bookmark.activityId)
.font(.headline)
if let folder = bookmark.folder {
Text("Folder: \(folder)")
.font(.caption)
}
}
}
if bookmarkList.hasMore {
ProgressView()
.task {
try? await bookmarkList.loadMore()
}
}
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let bookmarkList = try await client.queryBookmarks(
request: .init(filterConditions: [:])
)Real-time Updates
Subscribe to real-time updates on a feed. When you call getOrCreate() on a feed, the state layer automatically subscribes to WebSocket events. Activities, followers, members, and notification status update in real time without additional code.
Example
import SwiftUI
import StreamCore
import StreamFeeds
struct RealTimeFeedView: View {
@ObservedObject var feedState: FeedState
let feed: Feed
var body: some View {
VStack {
// This list updates in real time as new activities arrive
List(feedState.activities, id: \.id) { activity in
VStack(alignment: .leading) {
Text(activity.type)
.font(.headline)
Text("By: \(activity.actor)")
.font(.subheadline)
}
}
.animation(.default, value: feedState.activities.count)
}
.task {
// getOrCreate subscribes to real-time updates automatically
try? await feed.getOrCreate()
}
}
}
// Setup
let client = FeedsClient(
apiKey: APIKey("<your_api_key>"),
user: User(id: "john"),
token: "<user_token>"
)
try await client.connect()
let feed = client.feed(for: FeedId(group: "user", id: "john"))
// Real-time updates flow through feed.state automatically
// No additional subscription code needed