├── .gitignore
├── CoordinatorSwiftUI WatchKit App
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── icon_1024@1x.png
│ │ ├── icon_24@2x.png
│ │ ├── icon_27.5@2x.png
│ │ ├── icon_29@2x.png
│ │ ├── icon_29@3x.png
│ │ ├── icon_40@2x.png
│ │ ├── icon_86@2x.png
│ │ └── icon_98@2x.png
│ └── Contents.json
├── Base.lproj
│ └── Interface.storyboard
└── Info.plist
├── CoordinatorSwiftUI WatchKit Extension
├── Assets.xcassets
│ ├── Complication.complicationset
│ │ ├── Circular.imageset
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── Extra Large.imageset
│ │ │ └── Contents.json
│ │ ├── Graphic Bezel.imageset
│ │ │ └── Contents.json
│ │ ├── Graphic Circular.imageset
│ │ │ └── Contents.json
│ │ ├── Graphic Corner.imageset
│ │ │ └── Contents.json
│ │ ├── Graphic Large Rectangular.imageset
│ │ │ └── Contents.json
│ │ ├── Modular.imageset
│ │ │ └── Contents.json
│ │ └── Utilitarian.imageset
│ │ │ └── Contents.json
│ └── Contents.json
├── Info.plist
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
└── SourceCode
│ ├── CommonViews
│ └── ContextMenu
│ │ ├── LogoutButtonView.swift
│ │ └── RefreshButtonView.swift
│ ├── Coordinators
│ ├── ApplicationCoordinator.swift
│ └── Coordinator.swift
│ ├── ExtensionDelegate
│ └── ExtensionDelegate.swift
│ ├── Extensions
│ ├── Binding+Convenience.swift
│ └── View+Convertion.swift
│ ├── LifeCycle
│ ├── ApplicationView.swift
│ └── HostingController.swift
│ ├── Managers
│ └── UserManager.swift
│ ├── Models
│ ├── Author.swift
│ ├── Thumbnail.swift
│ └── User.swift
│ ├── Modules
│ ├── Authentication
│ │ ├── Coordinators
│ │ │ └── AuthenticationCoordinator.swift
│ │ ├── ViewModels
│ │ │ └── UserListViewModel.swift
│ │ └── Views
│ │ │ └── AuthenticationView.swift
│ └── Authors
│ │ ├── Coordinators
│ │ └── AuthorsCoordinator.swift
│ │ └── Modules
│ │ ├── AuthorProfileDetail
│ │ ├── ViewModels
│ │ │ └── AuthorProfileDetailViewModel.swift
│ │ └── Views
│ │ │ └── AuthorProfileDetailView.swift
│ │ └── AuthorsList
│ │ ├── Enum
│ │ └── AuthorsListViewModel+State.swift
│ │ ├── ViewModels
│ │ └── AuthorsListViewModel.swift
│ │ └── Views
│ │ ├── AuthorRowView.swift
│ │ └── AuthorsListView.swift
│ ├── Protocols
│ └── KeyPathUpdatable.swift
│ ├── Providers
│ └── Authors
│ │ ├── AuthorsProvider.swift
│ │ └── Mocks
│ │ ├── AuthorsProviderFailureMock.swift
│ │ └── AuthorsProviderSuccessMock.swift
│ ├── Stores
│ └── AuthorsStore.swift
│ └── Stubs
│ ├── Authors
│ └── Authors.json
│ ├── AuthorsStub.swift
│ ├── File.swift
│ ├── Users
│ └── Users.json
│ └── UsersStub.swift
├── CoordinatorSwiftUI.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── CoordinatorSwiftUI WatchKit App.xcscheme
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/xcode,swift
3 | # Edit at https://www.gitignore.io/?templates=xcode,swift
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Xcode Patch
32 | *.xcodeproj/*
33 | !*.xcodeproj/project.pbxproj
34 | !*.xcodeproj/xcshareddata/
35 | !*.xcworkspace/contents.xcworkspacedata
36 | /*.gcno
37 |
38 | ### Xcode Patch ###
39 | **/xcshareddata/WorkspaceSettings.xcsettings
40 |
41 | # End of https://www.gitignore.io/api/xcode,swift
42 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "24x24",
5 | "idiom" : "watch",
6 | "filename" : "icon_24@2x.png",
7 | "scale" : "2x",
8 | "role" : "notificationCenter",
9 | "subtype" : "38mm"
10 | },
11 | {
12 | "size" : "27.5x27.5",
13 | "idiom" : "watch",
14 | "filename" : "icon_27.5@2x.png",
15 | "scale" : "2x",
16 | "role" : "notificationCenter",
17 | "subtype" : "42mm"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "watch",
22 | "filename" : "icon_29@2x.png",
23 | "role" : "companionSettings",
24 | "scale" : "2x"
25 | },
26 | {
27 | "size" : "29x29",
28 | "idiom" : "watch",
29 | "filename" : "icon_29@3x.png",
30 | "role" : "companionSettings",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "watch",
36 | "filename" : "icon_40@2x.png",
37 | "scale" : "2x",
38 | "role" : "appLauncher",
39 | "subtype" : "38mm"
40 | },
41 | {
42 | "size" : "44x44",
43 | "idiom" : "watch",
44 | "scale" : "2x",
45 | "role" : "appLauncher",
46 | "subtype" : "40mm"
47 | },
48 | {
49 | "size" : "50x50",
50 | "idiom" : "watch",
51 | "scale" : "2x",
52 | "role" : "appLauncher",
53 | "subtype" : "44mm"
54 | },
55 | {
56 | "size" : "86x86",
57 | "idiom" : "watch",
58 | "filename" : "icon_86@2x.png",
59 | "scale" : "2x",
60 | "role" : "quickLook",
61 | "subtype" : "38mm"
62 | },
63 | {
64 | "size" : "98x98",
65 | "idiom" : "watch",
66 | "filename" : "icon_98@2x.png",
67 | "scale" : "2x",
68 | "role" : "quickLook",
69 | "subtype" : "42mm"
70 | },
71 | {
72 | "size" : "108x108",
73 | "idiom" : "watch",
74 | "scale" : "2x",
75 | "role" : "quickLook",
76 | "subtype" : "44mm"
77 | },
78 | {
79 | "size" : "1024x1024",
80 | "idiom" : "watch-marketing",
81 | "filename" : "icon_1024@1x.png",
82 | "scale" : "1x"
83 | }
84 | ],
85 | "info" : {
86 | "version" : 1,
87 | "author" : "xcode"
88 | }
89 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_1024@1x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_24@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_24@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_27.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_27.5@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_86@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_86@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_98@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unnamedd/CoordinatorSwiftUI/f9b02587ac931007650a16c3b9bcf4ae2e52f7ae/CoordinatorSwiftUI WatchKit App/Assets.xcassets/AppIcon.appiconset/icon_98@2x.png
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Base.lproj/Interface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Authors
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | UISupportedInterfaceOrientations
24 |
25 | UIInterfaceOrientationPortrait
26 | UIInterfaceOrientationPortraitUpsideDown
27 |
28 | WKWatchKitApp
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "idiom" : "watch",
5 | "filename" : "Circular.imageset",
6 | "role" : "circular"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "filename" : "Extra Large.imageset",
11 | "role" : "extra-large"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "filename" : "Graphic Bezel.imageset",
16 | "role" : "graphic-bezel"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "filename" : "Graphic Circular.imageset",
21 | "role" : "graphic-circular"
22 | },
23 | {
24 | "idiom" : "watch",
25 | "filename" : "Graphic Corner.imageset",
26 | "role" : "graphic-corner"
27 | },
28 | {
29 | "idiom" : "watch",
30 | "filename" : "Graphic Large Rectangular.imageset",
31 | "role" : "graphic-large-rectangular"
32 | },
33 | {
34 | "idiom" : "watch",
35 | "filename" : "Modular.imageset",
36 | "role" : "modular"
37 | },
38 | {
39 | "idiom" : "watch",
40 | "filename" : "Utilitarian.imageset",
41 | "role" : "utilitarian"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "version" : 1,
26 | "author" : "xcode"
27 | }
28 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | CoordinatorSwiftUI WatchKit Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | WKAppBundleIdentifier
28 | codes.unnamedd.CoordinatorSwiftUI.watchkitapp
29 |
30 | NSExtensionPointIdentifier
31 | com.apple.watchkit
32 |
33 | WKExtensionDelegateClassName
34 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
35 | WKWatchOnly
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/CommonViews/ContextMenu/LogoutButtonView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct LogoutButtonView: View {
4 | var body: some View {
5 | let configuration = UIImage.SymbolConfiguration(pointSize: 30, weight: .light, scale: .large)
6 | let compose = UIImage(systemName: "square.and.pencil", withConfiguration: configuration)!
7 |
8 | return ZStack {
9 | Image(uiImage: compose)
10 | Text("Logout")
11 | .fontWeight(.bold)
12 | }
13 | }
14 | }
15 |
16 | struct LogoutButtonView_Previews: PreviewProvider {
17 | static var previews: some View {
18 | LogoutButtonView()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/CommonViews/ContextMenu/RefreshButtonView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct RefreshButtonView: View {
4 | var body: some View {
5 | let configuration = UIImage.SymbolConfiguration(pointSize: 30, weight: .light, scale: .large)
6 | let compose = UIImage(systemName: "arrow.counterclockwise.circle", withConfiguration: configuration)!
7 |
8 | return ZStack {
9 | Image(uiImage: compose)
10 | Text("Refresh")
11 | .fontWeight(.bold)
12 | }
13 | }
14 | }
15 |
16 | struct RefreshButtonView_Previews: PreviewProvider {
17 | static var previews: some View {
18 | RefreshButtonView()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/Coordinators/ApplicationCoordinator.swift:
--------------------------------------------------------------------------------
1 | import Combine
2 | import SwiftUI
3 |
4 | final class ApplicationCoordinator: Coordinator, ObservableObject {
5 |
6 | @Published
7 | private var userManager = UserManager.shared
8 |
9 | // MARK: - Init
10 | override init() {
11 | super.init()
12 | }
13 |
14 | override func start() -> AnyView {
15 | guard userManager.isUserAuthenticated else {
16 | return startAuthentication()
17 | }
18 |
19 | return startAuthors()
20 | }
21 |
22 | func startAuthentication() -> AnyView {
23 | let authenticationCoordinator = AuthenticationCoordinator()
24 | authenticationCoordinator.delegate = self
25 |
26 | addChild(authenticationCoordinator)
27 |
28 | return authenticationCoordinator.start()
29 | }
30 |
31 | func startAuthors() -> AnyView {
32 | let authorsCoordinator = AuthorsCoordinator()
33 | authorsCoordinator.delegate = self
34 |
35 | addChild(authorsCoordinator)
36 |
37 | return authorsCoordinator.start()
38 | }
39 | }
40 |
41 | // MARK: - AuthenticationCoordinator Delegate
42 |
43 | extension ApplicationCoordinator: AuthenticationCoordinatorDelegate {
44 | func authenticationCoordinator(_ coordinator: AuthenticationCoordinator, didFinishAuthentication user: User) {
45 | removeChild(coordinator)
46 |
47 | userManager.set(user)
48 | self.objectWillChange.send()
49 | }
50 | }
51 |
52 | // MARK: - AuthorsCoordinator Delegate
53 |
54 | extension ApplicationCoordinator: AuthorsCoordinatorDelegate {
55 | func authorsCoordinatorDidFinish(_ coordinator: AuthorsCoordinator) {
56 | removeChild(coordinator)
57 |
58 | userManager.clearData()
59 | self.objectWillChange.send()
60 | }
61 | }
62 |
63 |
64 |
65 | // MARK: - Dummy
66 |
67 | #if DEBUG
68 |
69 | extension ApplicationCoordinator {
70 | static func makeDummy() -> ApplicationCoordinator {
71 | ApplicationCoordinator()
72 | }
73 | }
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/Coordinators/Coordinator.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | open class Coordinator {
4 |
5 | weak var parent: Coordinator?
6 | private(set) var children: Set
7 |
8 | init() {
9 | children = Set()
10 | }
11 |
12 | final func addChild(_ coordinator: Coordinator) {
13 | coordinator.parent = self
14 | children.insert(coordinator)
15 | }
16 |
17 | final func removeChild(_ coordinator: Coordinator) {
18 | children.remove(coordinator)
19 | }
20 |
21 | final func removeAllChildren() {
22 | children.removeAll()
23 | }
24 |
25 | open func start() -> AnyView {
26 | fatalError("Subclasses must implement \(#function)")
27 | }
28 | }
29 |
30 | extension Coordinator: Hashable {
31 | public func hash(into hasher: inout Hasher) {
32 | hasher.combine(ObjectIdentifier(self).hashValue)
33 | }
34 | }
35 |
36 | extension Coordinator: Equatable {
37 | public static func ==(lhs: Coordinator, rhs: Coordinator) -> Bool {
38 | return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/ExtensionDelegate/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | import WatchKit
2 |
3 | final class ExtensionDelegate: NSObject, WKExtensionDelegate {}
4 |
--------------------------------------------------------------------------------
/CoordinatorSwiftUI WatchKit Extension/SourceCode/Extensions/Binding+Convenience.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | extension Binding {
4 | init