Skip to content
Open
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DEFAULT_GOAL := help

SIMULATOR_DESTINATION := OS=26.0,name=iPhone 17
SIMULATOR_DESTINATION := platform=iOS Simulator,name=iPhone 17

.PHONY: help
help: ## Display this help menu
Expand Down
2 changes: 1 addition & 1 deletion ios/Demo-iOS/Gutenberg.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@
repositoryURL = "https://github.com/Automattic/wordpress-rs";
requirement = {
kind = revision;
revision = "alpha-20250926";
revision = "alpha-20260203";
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ios/Demo-iOS/Sources/Views/EditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ private final class EditorViewModel {

extension EditorConfiguration {
static let bundled = EditorConfigurationBuilder(
postType: "post",
postType: .post,
siteURL: URL(string: "https://example.com")!,
siteApiRoot: URL(string: "https://example.com/wp-json")!
)
Expand Down
147 changes: 147 additions & 0 deletions ios/Demo-iOS/Sources/Views/PostsListView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import SwiftUI
import WordPressAPI
import GutenbergKit

struct PostsListView: View {

@Environment(\.navigation)
private var navigation

@State
private var viewModel: PostsListViewModel

init(client: WordPressAPI, postTypeDetails: PostTypeDetails, editorConfiguration: EditorConfiguration, editorDependencies: EditorDependencies?) {
self.viewModel = PostsListViewModel(
client: client,
postTypeDetails: postTypeDetails,
editorConfiguration: editorConfiguration,
editorDependencies: editorDependencies
)
}

var body: some View {
Group {
if viewModel.isLoading && viewModel.posts.isEmpty {
ProgressView("Loading entries...")
} else if let error = viewModel.error {
ContentUnavailableView {
Label("Error Loading Entries", systemImage: "exclamationmark.triangle")
} description: {
Text(error.localizedDescription)
} actions: {
Button("Retry") {
Task {
await viewModel.loadPosts()
}
}
}
} else if viewModel.posts.isEmpty {
ContentUnavailableView {
Label("No Entires", systemImage: "doc.text")
} description: {
Text("No entries found for this post type.")
}
} else {
List(viewModel.posts, id: \.id) { post in
Button {
openPost(post)
} label: {
VStack(alignment: .leading, spacing: 4) {
Text(post.title?.rendered ?? "")
.font(.headline)
if let excerpt = post.excerpt?.rendered, !excerpt.isEmpty {
Text(excerpt.strippingHTML())
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(2)
}
}
}
}
.listStyle(.plain)
}
}
.navigationTitle(viewModel.postTypeDetails.restBase.capitalized)
.task {
await viewModel.loadPosts()
}
}

private func openPost(_ post: AnyPostWithEditContext) {
let configuration = viewModel.editorConfiguration.toBuilder()
.setPostType(viewModel.postTypeDetails)
.setPostID(Int(post.id))
.setTitle(post.title?.raw ?? "")
.setContent(post.content.raw ?? "")
.build()
Comment on lines +71 to +76
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't take into consideration the toggles controlling the native inserter and network logging. The result is the editor opening with the default false value for both.

This isn't a regression with the GBK library, but it's an oddity for the demo app. So, not a blocker, but we ideally address this oversight.


let editor = RunnableEditor(
configuration: configuration,
dependencies: viewModel.editorDependencies
)

navigation.present(editor)
}
}

@Observable
class PostsListViewModel {
var posts: [AnyPostWithEditContext] = []
var isLoading = false
var error: Error?

let client: WordPressAPI
let postTypeDetails: PostTypeDetails
let editorConfiguration: EditorConfiguration
let editorDependencies: EditorDependencies?

init(client: WordPressAPI, postTypeDetails: PostTypeDetails, editorConfiguration: EditorConfiguration, editorDependencies: EditorDependencies?) {
self.client = client
self.postTypeDetails = postTypeDetails
self.editorConfiguration = editorConfiguration
self.editorDependencies = editorDependencies
}

@MainActor
func loadPosts() async {
guard !isLoading else { return }

isLoading = true
error = nil
posts = []

defer { isLoading = false }

do {
let endpointType: PostEndpointType
if postTypeDetails.postType == "post" {
endpointType = .posts
} else if postTypeDetails.postType == "page" {
endpointType = .pages
} else {
endpointType = .custom(postTypeDetails.restBase)
}

var currentPage: UInt32 = 1
let perPage: UInt32 = 20
while true {
let params = PostListParams(page: currentPage, perPage: perPage, status: [.custom("any")])
let fetched = try await client.posts.listWithEditContext(type: endpointType, params: params).data
self.posts.append(contentsOf: fetched)

if fetched.count < perPage {
break
}
currentPage += 1
}
} catch {
self.error = error
}
}
}

private extension String {
func strippingHTML() -> String {
self.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression)
}
}
Loading
Loading