Skip to content

Commit

Permalink
165
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Oct 25, 2021
1 parent be72141 commit 9d205ac
Show file tree
Hide file tree
Showing 18 changed files with 1,434 additions and 0 deletions.
5 changes: 5 additions & 0 deletions 0163-navigation-pt4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [SwiftUI Navigation: Sheets and Popovers, Part 2](https://www.pointfree.co/episodes/ep163-swiftui-navigation-sheets-popovers-part-2)
>
> This week we'll explore how to drive a sheet with optional state and how to facilitate communication between the sheet and the view presenting it. In the process we will discover a wonderful binding transformation for working with optionals.
5 changes: 5 additions & 0 deletions 0164-navigation-pt5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [SwiftUI Navigation: Sheets and Popovers, Part 3](https://www.pointfree.co/episodes/ep164-swiftui-navigation-sheets-popovers-part-3)
>
> Now that we've built up the tools needed to bind application state to navigation, let's exercise them. We'll quickly add two more features to our application, beef up our navigation tools, and even write unit tests that assert against navigation and deep-linking.
5 changes: 5 additions & 0 deletions 0165-navigation-pt6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [SwiftUI Navigation: Links, Part 1](https://www.pointfree.co/episodes/ep165-swiftui-navigation-links-part-1)
>
> It's time to explore the most complex form of navigation in SwiftUI: links! We’ll start with some simpler flavors of `NavigationLink` to see how they work, how they compare with other navigation APIs, and how they interact with the tools we've built in this series.

Large diffs are not rendered by default.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SwiftUI

enum Tab {
case one, inventory, three
}

class AppViewModel: ObservableObject {
@Published var inventoryViewModel: InventoryViewModel
@Published var selectedTab: Tab

init(
inventoryViewModel: InventoryViewModel = .init(),
selectedTab: Tab = .one
) {
self.inventoryViewModel = inventoryViewModel
self.selectedTab = selectedTab
}
}

struct ContentView: View {
@ObservedObject var viewModel: AppViewModel

var body: some View {
TabView(selection: self.$viewModel.selectedTab) {
Button("Go to 2nd tab") {
self.viewModel.selectedTab = .inventory
}
.tabItem { Text("One") }
.tag(Tab.one)

NavigationView {
InventoryView(viewModel: self.viewModel.inventoryViewModel)
}
.tabItem { Text("Inventory") }
.tag(Tab.inventory)

Text("Three")
.tabItem { Text("Three") }
.tag(Tab.three)
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewModel: .init(selectedTab: .inventory))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import IdentifiedCollections
import SwiftUI

struct Item: Equatable, Identifiable {
let id = UUID()
var name: String
var color: Color?
var status: Status

enum Status: Equatable {
case inStock(quantity: Int)
case outOfStock(isOnBackOrder: Bool)

var isInStock: Bool {
guard case .inStock = self else { return false }
return true
}
}

struct Color: Equatable, Hashable {
var name: String
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0

static var defaults: [Self] = [
.red,
.green,
.blue,
.black,
.yellow,
.white,
]

static let red = Self(name: "Red", red: 1)
static let green = Self(name: "Green", green: 1)
static let blue = Self(name: "Blue", blue: 1)
static let black = Self(name: "Black")
static let yellow = Self(name: "Yellow", red: 1, green: 1)
static let white = Self(name: "White", red: 1, green: 1, blue: 1)

var swiftUIColor: SwiftUI.Color {
.init(red: self.red, green: self.green, blue: self.blue)
}
}
}

class InventoryViewModel: ObservableObject {
@Published var inventory: IdentifiedArrayOf<ItemRowViewModel>
@Published var itemToAdd: Item?

init(
inventory: IdentifiedArrayOf<ItemRowViewModel> = [],
itemToAdd: Item? = nil
) {
self.itemToAdd = itemToAdd
self.inventory = []

for itemRowViewModel in inventory {
self.bind(itemRowViewModel: itemRowViewModel)
}
}

private func bind(itemRowViewModel: ItemRowViewModel) {
itemRowViewModel.onDelete = { [weak self, item = itemRowViewModel.item] in
withAnimation {
self?.delete(item: item)
}
}
itemRowViewModel.onDuplicate = { [weak self] item in
withAnimation {
self?.add(item: item)
}
}
self.inventory.append(itemRowViewModel)
}

func delete(item: Item) {
withAnimation {
_ = self.inventory.remove(id: item.id)
}
}

func add(item: Item) {
withAnimation {
self.bind(itemRowViewModel: .init(item: item))
self.itemToAdd = nil
}
}

func addButtonTapped() {
self.itemToAdd = .init(name: "", color: nil, status: .inStock(quantity: 1))

Task { @MainActor in
try await Task.sleep(nanoseconds: 500 * NSEC_PER_MSEC)
self.itemToAdd?.name = "Bluetooth Keyboard"
}
}

func cancelButtonTapped() {
self.itemToAdd = nil
}
}

struct InventoryView: View {
@ObservedObject var viewModel: InventoryViewModel

var body: some View {
List {
ForEach(
self.viewModel.inventory,
content: ItemRowView.init(viewModel:)
)
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Add") { self.viewModel.addButtonTapped() }
}
}
.navigationTitle("Inventory")
.sheet(unwrap: self.$viewModel.itemToAdd) { $itemToAdd in
NavigationView {
ItemView(item: $itemToAdd)
.navigationTitle("Add")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { self.viewModel.cancelButtonTapped() }
}
ToolbarItem(placement: .primaryAction) {
Button("Save") { self.viewModel.add(item: itemToAdd) }
}
}
}
}
}
}

struct TestView: View {
@State var collection = [1, 2, 3]

var body: some View {
ForEach(self.$collection, id: \.self) { $element in

}
}
}

struct InventoryView_Previews: PreviewProvider {
static var previews: some View {
let keyboard = Item(name: "Keyboard", color: .blue, status: .inStock(quantity: 100))

NavigationView {
InventoryView(
viewModel: .init(
inventory: [
.init(item: keyboard),
.init(item: Item(name: "Charger", color: .yellow, status: .inStock(quantity: 20))),
.init(item: Item(name: "Phone", color: .green, status: .outOfStock(isOnBackOrder: true))),
.init(item: Item(name: "Headphones", color: .green, status: .outOfStock(isOnBackOrder: false))),
],
itemToAdd: nil
)
)
}
}
}
Loading

0 comments on commit 9d205ac

Please sign in to comment.