Skip to content

Commit

Permalink
Cleanup comments for new view accessor
Browse files Browse the repository at this point in the history
Also minor code adjustments for beautz.
  • Loading branch information
helje5 committed Apr 27, 2022
1 parent 2e2f7c9 commit 18c5dba
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 94 deletions.
84 changes: 35 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@ More details will be posted but to get started.

class HomePage: ViewController {

struct ContentView: View {

var body: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

Spacer()
}
var view: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

Spacer()
}
}
}
Expand All @@ -58,16 +55,13 @@ More details will be posted but to get started.

class Settings: ViewController {

struct ContentView: View {

var body: some View {
VStack {
Text("Welcome to Settings!")
.font(.title)
.padding()

Spacer()
}
var view: some View { // the View being controlled
VStack {
Text("Welcome to Settings!")
.font(.title)
.padding()

Spacer()
}
}
}
Expand All @@ -82,24 +76,19 @@ More details will be posted but to get started.
show(Settings()) // or `present(Settings())`
}

struct ContentView: View {

@EnvironmentObject private var viewController : HomePage

var body: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

Divider()

Button(action: viewController.configureApp) {
Label("Configure", systemImage: "gear")
}
var view: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

Spacer()
Divider()

Button(action: self.configureApp) {
Label("Configure", systemImage: "gear")
}

Spacer()
}
}
}
Expand Down Expand Up @@ -144,20 +133,17 @@ inline a `NavigationLink`, use `PushLink`, which wraps that.

class HomePage: ViewController {

struct ContentView: View {

var body: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

Divider()
var view: some View {
VStack {
Text("Welcome to MWC!")
.font(.title)
.padding()

PushLink("Open Settings", to: Settings())

Spacer()
}
Divider()

PushLink("Open Settings", to: Settings())

Spacer()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,11 @@ open class NavigationController<RootVC>: ViewController, _NavigationController

// MARK: - View

public struct ContentView: View {

@EnvironmentObject private var viewController : NavigationController

public init() {}

public var body: some View {
NavigationView {
viewController._rootViewController.view
.controlled(by: viewController._rootViewController)
.navigationTitle(viewController._rootViewController.navigationTitle)
}
public var view: some View {
NavigationView {
_rootViewController.view
.controlled(by: _rootViewController)
.navigationTitle(_rootViewController.navigationTitle)
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions Sources/ViewController/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import SwiftUI
* i.e. one which starts a new VC hierarchy.
* Usually only one root VC is used per scene.
*
* Checkout the ``View/main`` modifier for the more general solution.
*
* E.g. this could be used in the `ContentView` of an app like this:
* ```swift
* struct ContentView: View {
Expand Down
12 changes: 6 additions & 6 deletions Sources/ViewController/NavigationLink/PushLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ import SwiftUI
*
* Content View Example:
* ```swift
* struct ContentView: View {
* var body: some View {
* class HomePage: ViewController {
* var view: some View {
* PushLink("Preferences…", to: PreferencesPage())
* }
* }
* ```
*
* Explicit View Example:
* ```swift
* struct ContentView: View {
* var body: some View {
* class HomePage: ViewController {
* var view: some View {
* PushLink(to: PreferencesPage(), using: Text("Prefs!") {
* Text("Preferences…")
* }
Expand Down Expand Up @@ -200,7 +200,7 @@ public struct PushLink<VC, CV, Label>: View
extension PushLink {

/**
* Create a ``PushLink`` that is using the ``ViewController/ContentView``
* Create a ``PushLink`` that is using the ``ViewController/view``
* as the destination.
*
* Example:
Expand All @@ -221,7 +221,7 @@ extension PushLink {
}

/**
* Create a ``PushLink`` that is using the ``ViewController/ContentView``
* Create a ``PushLink`` that is using the ``ViewController/view``
* as the destination.
*
* Example:
Expand Down
9 changes: 9 additions & 0 deletions Sources/ViewController/Presentations/PresentationMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ import SwiftUI
* ```swift
* public struct ContentView: View {
* @Environment(\.viewControllerPresentationMode) private var mode
*
* var body: some View {
* if mode == .sheet {
* Text("I'm in a sheet!")
* }
* else {
* Text("I'm in a sheet, NOT!")
* }
* }
* }
* ```
*/
Expand Down
54 changes: 47 additions & 7 deletions Sources/ViewController/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import SwiftUI
import Combine

/**
* A ViewController.
* A ``ViewController``.
*
* TODO: lotsa more documentation
*
* In WebObjects those would be called `WOComponent`s and are accessible
* using the Environment (`WOContext` in WebObjects).
Expand All @@ -19,15 +21,15 @@ import Combine
* The lifecycle events also do not reflect whether the VC is "really" on
* screen, just whether it has been presented.
*
* There are two parts to presenting a ViewController:
* ### Custom Presentation
*
* There are two parts to presenting a ViewController in a custom way:
* - Call `present` on the active viewController with the instance of the new,
* child ViewController. The active VC can be accessed using
* `@EnvironmentObject private var viewController : ViewController`
* (or the specific VC subclass)
* - To choose the presentation style, attach it to the View, for example:
* `.presentInNavigation(ChildVC.self) { ChildVC.ContentView() }`
*
* TODO: lotsa more documentation
*/
public protocol ViewController: _ViewController, ObservableObject, Identifiable
{
Expand All @@ -44,9 +46,19 @@ public protocol ViewController: _ViewController, ObservableObject, Identifiable
* E.g. there could be a different main View for macOS and for iOS.
*
* But having a single associated `ContentView` allows for more convenient
* API for that common case.
* APIs for that common case.
*
* Example:
* Implicit View via `view` accessor:
* ```swift
* class Contacts: ViewController {
*
* var view: some View {
* Text("The Contacts!")
* }
* }
* ```
*
* Implicit View, explicit class:
* ```swift
* class Contacts: ViewController {
*
Expand All @@ -67,6 +79,7 @@ public protocol ViewController: _ViewController, ObservableObject, Identifiable
* Dirty trick to let the user avoid the need to explicitly specify the
* `ViewControllerView` when declaring Views within the scope of a
* ViewController.
*
* Example:
* ```swift
* class Contacts: ViewController {
Expand All @@ -80,7 +93,34 @@ public protocol ViewController: _ViewController, ObservableObject, Identifiable
typealias View = ViewControllerView

/**
* Instantiates the ``ContentView`` associated with the ``ViewController``.
* Returns the ``ContentView`` associated with the ``ViewController``.
*
* One way to specify an associated ``View`` for the controller is by
* overriding this property, for example:
* ```swift
* class Contacts: ViewController {
*
* var view: some View {
* Text("The Contacts!")
* }
* }
* ```
*
* Another way is to use a ``ViewControllerView`` (just a plain `View` w/
* an `init` method w/o arguments, used to instantiate the `View`):
* ```swift
* class Contacts: ViewController {
*
* struct ContentView: View {
*
* @EnvironmentObject var viewController: Contacts
*
* var body: some View {
* Text("The Contacts!")
* }
* }
* }
* ```
*/
@ViewBuilder var view : ContentView { get }

Expand Down
7 changes: 7 additions & 0 deletions Sources/ViewController/ViewController/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import SwiftUI

public extension ViewController where ContentView: ViewControllerView {

/**
* The default implementation of the user's ``ViewController`` doesn't
* implement the ``ViewController/view`` method,
* but _does_ have an associated ``View/ContentView`` specified. In this case
* the `ContentView` needs to be a ``ViewControllerView`` (which just adds
* the empty `init` to `View`).
*/
@inlinable
@ViewBuilder var view : ContentView { ContentView() }
}
Expand Down
22 changes: 4 additions & 18 deletions Sources/ViewController/ViewControllerEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ public extension EnvironmentValues {
}

/**
* Allows access to the ``ViewController``, w/o having the View refreshed if
* the VC changes.
* Allows access to the ``ViewController``, w/o having the `View` refreshed if
* the ViewController changes.
*
* I.e. an "unobserved object".
*
* Can be used like this:
* ```swift
Expand Down Expand Up @@ -75,22 +77,6 @@ public extension View {
// Note: Also used internally during presentation.
self
.modifier(AutoPresentationViewModifier(viewController: viewController))
.modifier(ControlledViewModifier(viewController: viewController))
}
}

// Push the VC into the environment by three means:
// - as an EnvironmentObject using its concrete class
// - type-erased, as an ``AnyViewController`` EnvironmentObject
// - as a plain `viewController` environment key (w/o state observation)
fileprivate struct ControlledViewModifier<VC>: ViewModifier
where VC: ViewController
{

let viewController : VC

func body(content: Content) -> some View {
content
.environmentObject(viewController)
.environmentObject(AnyViewController(viewController))
.environment(\.viewController, viewController)
Expand Down

0 comments on commit 18c5dba

Please sign in to comment.