iOS · SwiftUI · SDK 1.0.1
Feature Plans
Let app users explore your plans, vote on features, and follow your roadmap.
Complete the iOS quickstart first. These examples use the configured app and the MobileJoeUI package product.
Create a feature plan
In the dashboard, open Feature Plans and save a plan with status Open. Every status except Draft is visible in your app.
Show the list
Add this screen to your app, or move its navigation link into your existing navigation stack:
import SwiftUI
import MobileJoeUI
struct FeedbackView: View {
var body: some View {
NavigationStack {
List {
NavigationLink("Feature Plans") {
FeaturePlansView(
configuration: .standard(recipient: "support@example.com"),
presentationMode: .inNavigationStack
)
}
}
.navigationTitle("Feedback")
}
}
}
FeaturePlansView loads data, fetches additional pages while scrolling, and supports pull to refresh. Tapping a plan opens its details. The vote button adds a vote; tapping it again removes that vote.
Search matches titles and descriptions. The toolbar menu offers newest-first or score sorting and the status filters.
Present a sheet
Use .asSheet to get the SDK's navigation stack and close button:
import SwiftUI
import MobileJoeUI
struct FeaturePlansButton: View {
@State private var showingPlans = false
var body: some View {
Button("Feature Plans") { showingPlans = true }
.sheet(isPresented: $showingPlans) {
FeaturePlansView(
configuration: .standard(recipient: "support@example.com"),
presentationMode: .asSheet
)
}
}
}
Suggestions and deep links
Replace support@example.com with your support address. The suggestion button opens the user's email app; it does not create a feature plan. Use .standard(recipient: "") to hide it. For custom localized email content, use FeaturePlansView.Configuration(recipient:subject:body:).
To open a specific plan, pass its ID as selectedFeaturePlanID: after presentationMode:. Your app handles incoming URLs and extracts the ID. Save a Deep link base URL in the Feature Plans settings to copy deep links in the dashboard.
Use your own UI
Import MobileJoe and keep an observable FeaturePlans() model in @State. Read all, and call load(), reload(), vote(_:), featurePlan(id:), or search(for:) on the main actor; set sorting and filtering to change the list.
Verify
Open your saved plan, vote twice, and confirm the score returns to its starting value. Change its dashboard status to Planned, refresh, and check the roadmap filter. If it is missing, check the selected filter and follow Troubleshooting.