Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ import StreamCore
public final class BookmarkFolderList: Sendable {
@MainActor private let stateBuilder: StateBuilder<BookmarkFolderListState>
private let bookmarksRepository: BookmarksRepository

init(query: BookmarkFoldersQuery, client: FeedsClient) {
bookmarksRepository = client.bookmarksRepository
self.query = query
let events = client.eventsMiddleware
stateBuilder = StateBuilder { BookmarkFolderListState(query: query, events: events) }
let eventPublisher = client.stateLayerEventPublisher
stateBuilder = StateBuilder { BookmarkFolderListState(query: query, eventPublisher: eventPublisher) }
}

public let query: BookmarkFoldersQuery

// MARK: - Accessing the State

/// An observable object representing the current state of the bookmark list.
@MainActor public var state: BookmarkFolderListState { stateBuilder.state }

// MARK: - Paginating the List of BookmarkFolders

@discardableResult
public func get() async throws -> [BookmarkFolderData] {
try await queryBookmarkFolders(with: query)
}

public func queryMoreBookmarkFolders(limit: Int? = nil) async throws -> [BookmarkFolderData] {
let nextQuery: BookmarkFoldersQuery? = await state.access { state in
guard let next = state.pagination?.next else { return nil }
Expand All @@ -44,9 +44,9 @@ public final class BookmarkFolderList: Sendable {
guard let nextQuery else { return [] }
return try await queryBookmarkFolders(with: nextQuery)
}

// MARK: - Private

private func queryBookmarkFolders(with query: BookmarkFoldersQuery) async throws -> [BookmarkFolderData] {
let result = try await bookmarksRepository.queryBookmarkFolders(with: query)
await state.didPaginate(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,29 @@ import Foundation
import StreamCore

@MainActor public class BookmarkFolderListState: ObservableObject {
private var webSocketObserver: WebSocketObserver?
lazy var changeHandlers: ChangeHandlers = makeChangeHandlers()

init(query: BookmarkFoldersQuery, events: WSEventsSubscribing) {
private var eventSubscription: StateLayerEventPublisher.Subscription?

init(query: BookmarkFoldersQuery, eventPublisher: StateLayerEventPublisher) {
self.query = query
webSocketObserver = WebSocketObserver(subscribing: events, handlers: changeHandlers)
subscribe(to: eventPublisher)
}

public let query: BookmarkFoldersQuery

/// All the paginated folders.
@Published public private(set) var folders: [BookmarkFolderData] = []

// MARK: - Pagination State

/// Last pagination information.
public private(set) var pagination: PaginationData?

/// Indicates whether there are more bookmark folders available to load.
public var canLoadMore: Bool { pagination?.next != nil }

/// The configuration used for the last query.
private(set) var queryConfig: QueryConfiguration<BookmarkFoldersFilter, BookmarkFoldersSortField>?

var bookmarksSorting: [Sort<BookmarkFoldersSortField>] {
if let sort = queryConfig?.sort, !sort.isEmpty {
return sort
Expand All @@ -42,26 +41,27 @@ import StreamCore
// MARK: - Updating the State

extension BookmarkFolderListState {
struct ChangeHandlers {
let bookmarkFolderRemoved: @MainActor (String) -> Void
let bookmarkFolderUpdated: @MainActor (BookmarkFolderData) -> Void
}

private func makeChangeHandlers() -> ChangeHandlers {
ChangeHandlers(
bookmarkFolderRemoved: { [weak self] id in
self?.folders.remove(byId: id)
},
bookmarkFolderUpdated: { [weak self] folder in
self?.folders.replace(byId: folder)
private func subscribe(to publisher: StateLayerEventPublisher) {
eventSubscription = publisher.subscribe { [weak self] event in
switch event {
case .bookmarkFolderDeleted(let folder):
_ = await self?.access { state in
state.folders.remove(byId: folder.id)
}
case .bookmarkFolderUpdated(let folder):
_ = await self?.access { state in
state.folders.replace(byId: folder)
}
default:
break
}
)
}
}

func access<T>(_ actions: @MainActor (BookmarkFolderListState) -> T) -> T {
actions(self)
}

func didPaginate(
with response: PaginationResult<BookmarkFolderData>,
for queryConfig: QueryConfiguration<BookmarkFoldersFilter, BookmarkFoldersSortField>
Expand Down
20 changes: 10 additions & 10 deletions Sources/StreamFeeds/StateLayer/PaginatedLists/BookmarkList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ import StreamCore
public final class BookmarkList: Sendable {
@MainActor private let stateBuilder: StateBuilder<BookmarkListState>
private let bookmarksRepository: BookmarksRepository

init(query: BookmarksQuery, client: FeedsClient) {
bookmarksRepository = client.bookmarksRepository
self.query = query
let events = client.eventsMiddleware
stateBuilder = StateBuilder { BookmarkListState(query: query, events: events) }
let eventPublisher = client.stateLayerEventPublisher
stateBuilder = StateBuilder { BookmarkListState(query: query, eventPublisher: eventPublisher) }
}

public let query: BookmarksQuery

// MARK: - Accessing the State

/// An observable object representing the current state of the bookmark list.
@MainActor public var state: BookmarkListState { stateBuilder.state }

// MARK: - Paginating the List of Bookmarks

@discardableResult
public func get() async throws -> [BookmarkData] {
try await queryBookmarks(with: query)
}

public func queryMoreBookmarks(limit: Int? = nil) async throws -> [BookmarkData] {
let nextQuery: BookmarksQuery? = await state.access { state in
guard let next = state.pagination?.next else { return nil }
Expand All @@ -44,9 +44,9 @@ public final class BookmarkList: Sendable {
guard let nextQuery else { return [] }
return try await queryBookmarks(with: nextQuery)
}

// MARK: - Private

private func queryBookmarks(with query: BookmarksQuery) async throws -> [BookmarkData] {
let result = try await bookmarksRepository.queryBookmarks(with: query)
await state.didPaginate(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,29 @@ import Foundation
import StreamCore

@MainActor public class BookmarkListState: ObservableObject {
private var webSocketObserver: WebSocketObserver?
lazy var changeHandlers: ChangeHandlers = makeChangeHandlers()

init(query: BookmarksQuery, events: WSEventsSubscribing) {
private var eventSubscription: StateLayerEventPublisher.Subscription?

init(query: BookmarksQuery, eventPublisher: StateLayerEventPublisher) {
self.query = query
webSocketObserver = WebSocketObserver(subscribing: events, handlers: changeHandlers)
subscribe(to: eventPublisher)
}

public let query: BookmarksQuery

/// All the paginated bookmarks.
@Published public private(set) var bookmarks: [BookmarkData] = []

// MARK: - Pagination State

/// Last pagination information.
public private(set) var pagination: PaginationData?

/// Indicates whether there are more bookmarks available to load.
public var canLoadMore: Bool { pagination?.next != nil }

/// The configuration used for the last query.
private(set) var queryConfig: QueryConfiguration<BookmarksFilter, BookmarksSortField>?

var bookmarkFoldersSorting: [Sort<BookmarksSortField>] {
if let sort = queryConfig?.sort, !sort.isEmpty {
return sort
Expand All @@ -42,41 +41,39 @@ import StreamCore
// MARK: - Updating the State

extension BookmarkListState {
/// Handlers for various state change events.
///
/// These handlers are called when WebSocket events are received and automatically update the state accordingly.
struct ChangeHandlers {
let bookmarkFolderRemoved: @MainActor (String) -> Void
let bookmarkFolderUpdated: @MainActor (BookmarkFolderData) -> Void
let bookmarkUpdated: @MainActor (BookmarkData) -> Void
}

private func makeChangeHandlers() -> ChangeHandlers {
ChangeHandlers(
bookmarkFolderRemoved: { [weak self] folderId in
self?.updateBookmarkFolder(with: folderId, changes: { $0.folder = nil })
},
bookmarkFolderUpdated: { [weak self] folder in
self?.updateBookmarkFolder(with: folder.id, changes: { $0.folder = folder })
},
bookmarkUpdated: { [weak self] feed in
// Only update, do not insert
self?.bookmarks.replace(byId: feed)
private func subscribe(to publisher: StateLayerEventPublisher) {
eventSubscription = publisher.subscribe { [weak self] event in
switch event {
case .bookmarkFolderDeleted(let folder):
await self?.access { state in
state.updateBookmarkFolder(with: folder.id, changes: { $0.folder = nil })
}
case .bookmarkFolderUpdated(let folder):
await self?.access { state in
state.updateBookmarkFolder(with: folder.id, changes: { $0.folder = folder })
}
case .bookmarkUpdated(let bookmark):
await self?.access { state in
// Only update, do not insert
state.bookmarks.replace(byId: bookmark)
}
default:
break
}
)
}
}

private func updateBookmarkFolder(with id: String, changes: (inout BookmarkData) -> Void) {
guard let index = bookmarks.firstIndex(where: { $0.folder?.id == id }) else { return }
var bookmark = bookmarks[index]
changes(&bookmark)
bookmarks[index] = bookmark
}

func access<T>(_ actions: @MainActor (BookmarkListState) -> T) -> T {
actions(self)
}

func didPaginate(
with response: PaginationResult<BookmarkData>,
for queryConfig: QueryConfiguration<BookmarksFilter, BookmarksSortField>
Expand Down
Loading