-
Notifications
You must be signed in to change notification settings - Fork 299
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
be72141
commit 9d205ac
Showing
18 changed files
with
1,434 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
535 changes: 535 additions & 0 deletions
535
0165-navigation-pt6/SwiftUINavigation/SwiftUINavigation.xcodeproj/project.pbxproj
Large diffs are not rendered by default.
Oops, something went wrong.
7 changes: 7 additions & 0 deletions
7
...wiftUINavigation/SwiftUINavigation.xcodeproj/project.xcworkspace/contents.xcworkspacedata
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
8 changes: 8 additions & 0 deletions
8
...ion/SwiftUINavigation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
11 changes: 11 additions & 0 deletions
11
...t6/SwiftUINavigation/SwiftUINavigation/Assets.xcassets/AccentColor.colorset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"colors" : [ | ||
{ | ||
"idiom" : "universal" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
...-pt6/SwiftUINavigation/SwiftUINavigation/Assets.xcassets/AppIcon.appiconset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
0165-navigation-pt6/SwiftUINavigation/SwiftUINavigation/Assets.xcassets/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
0165-navigation-pt6/SwiftUINavigation/SwiftUINavigation/ContentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
166 changes: 166 additions & 0 deletions
166
0165-navigation-pt6/SwiftUINavigation/SwiftUINavigation/Inventory.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) | ||
) | ||
} | ||
} | ||
} |
Oops, something went wrong.