-
Notifications
You must be signed in to change notification settings - Fork 0
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
f006735
commit 175c6e6
Showing
17 changed files
with
945 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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 | ||
} | ||
} |
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,35 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"idiom" : "universal", | ||
"platform" : "ios", | ||
"size" : "1024x1024" | ||
}, | ||
{ | ||
"appearances" : [ | ||
{ | ||
"appearance" : "luminosity", | ||
"value" : "dark" | ||
} | ||
], | ||
"idiom" : "universal", | ||
"platform" : "ios", | ||
"size" : "1024x1024" | ||
}, | ||
{ | ||
"appearances" : [ | ||
{ | ||
"appearance" : "luminosity", | ||
"value" : "tinted" | ||
} | ||
], | ||
"idiom" : "universal", | ||
"platform" : "ios", | ||
"size" : "1024x1024" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
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 | ||
} | ||
} |
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,18 @@ | ||
// | ||
// ContentView.swift | ||
// MyApp | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct ContentView: View { | ||
var body: some View { | ||
UserListView() | ||
} | ||
} | ||
|
||
#Preview { | ||
ContentView() | ||
} |
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,15 @@ | ||
// | ||
// User.swift | ||
// Boilerplate | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
// Models/User.swift | ||
import Foundation | ||
|
||
struct User: Identifiable { | ||
let id: UUID | ||
let name: String | ||
let age: Int | ||
} |
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,46 @@ | ||
// | ||
// MyApp.swift | ||
// MyApp | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
|
||
import SwiftUI | ||
|
||
@main | ||
struct MyApp: App { | ||
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate | ||
|
||
@Environment(\.scenePhase) var scenePhase | ||
|
||
var body: some Scene { | ||
WindowGroup { | ||
ContentView() | ||
} | ||
.onChange(of: scenePhase) { newPhase in | ||
switch newPhase { | ||
case .active: | ||
print("App is active") | ||
case .inactive: | ||
print("App is inactive") | ||
case .background: | ||
print("App is in background") | ||
@unknown default: | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
class AppDelegate: NSObject, UIApplicationDelegate { | ||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { | ||
// Notification | ||
UNUserNotificationCenter.current().delegate = self | ||
return true | ||
} | ||
} | ||
|
||
extension AppDelegate: UNUserNotificationCenterDelegate { | ||
// Notification | ||
} |
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 | ||
} | ||
} |
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,27 @@ | ||
// | ||
// UserService.swift | ||
// Boilerplate | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
// Services/UserService.swift | ||
import Combine | ||
import Foundation | ||
|
||
protocol UserServiceProtocol { | ||
func fetchUsers() -> AnyPublisher<[User], Never> | ||
} | ||
|
||
class UserService: UserServiceProtocol { | ||
func fetchUsers() -> AnyPublisher<[User], Never> { | ||
let users = [ | ||
User(id: UUID(), name: "Alice", age: 25), | ||
User(id: UUID(), name: "Bob", age: 30), | ||
User(id: UUID(), name: "Charlie", age: 35) | ||
] | ||
return Just(users) | ||
.delay(for: .seconds(1), scheduler: DispatchQueue.main) //Mock delay | ||
.eraseToAnyPublisher() | ||
} | ||
} |
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,31 @@ | ||
// | ||
// UserViewModel.swift | ||
// Boilerplate | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
// ViewModels/UserViewModel.swift | ||
import Combine | ||
import Foundation | ||
|
||
class UserViewModel: ObservableObject { | ||
@Published var users: [User] = [] | ||
@Published var isLoading: Bool = false | ||
private var cancellables = Set<AnyCancellable>() | ||
private let userService: UserServiceProtocol | ||
|
||
init(userService: UserServiceProtocol = UserService()) { | ||
self.userService = userService | ||
} | ||
|
||
func fetchUsers() { | ||
isLoading = true | ||
userService.fetchUsers() | ||
.sink { [weak self] users in | ||
self?.users = users | ||
self?.isLoading = false | ||
} | ||
.store(in: &cancellables) | ||
} | ||
} |
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,23 @@ | ||
// | ||
// UserDetailView.swift | ||
// Boilerplate | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
// Views/UserDetailView.swift | ||
import SwiftUI | ||
|
||
struct UserDetailView: View { | ||
let user: User | ||
|
||
var body: some View { | ||
VStack { | ||
Text("Name: \(user.name)") | ||
.font(.title) | ||
Text("Age: \(user.age)") | ||
.font(.subheadline) | ||
} | ||
.padding() | ||
} | ||
} |
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,33 @@ | ||
// | ||
// UserListView.swift | ||
// Boilerplate | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
// Views/UserListView.swift | ||
import SwiftUI | ||
|
||
struct UserListView: View { | ||
@StateObject private var viewModel = UserViewModel() | ||
|
||
var body: some View { | ||
NavigationView { | ||
VStack { | ||
if viewModel.isLoading { | ||
ProgressView("Loading...") | ||
} else { | ||
List(viewModel.users) { user in | ||
NavigationLink(destination: UserDetailView(user: user)) { | ||
Text(user.name) | ||
} | ||
} | ||
} | ||
} | ||
.navigationBarTitle(Text("Users"), displayMode: .automatic) | ||
.onAppear { | ||
viewModel.fetchUsers() | ||
} | ||
} | ||
} | ||
} |
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,17 @@ | ||
// | ||
// MyAppTests.swift | ||
// MyAppTests | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
import Testing | ||
@testable import MyApp | ||
|
||
struct MyAppTests { | ||
|
||
@Test func example() async throws { | ||
// Write your test here and use APIs like `#expect(...)` to check expected conditions. | ||
} | ||
|
||
} |
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,43 @@ | ||
// | ||
// MyAppUITests.swift | ||
// MyAppUITests | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
import XCTest | ||
|
||
final class MyAppUITests: XCTestCase { | ||
|
||
override func setUpWithError() throws { | ||
// Put setup code here. This method is called before the invocation of each test method in the class. | ||
|
||
// In UI tests it is usually best to stop immediately when a failure occurs. | ||
continueAfterFailure = false | ||
|
||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. | ||
} | ||
|
||
override func tearDownWithError() throws { | ||
// Put teardown code here. This method is called after the invocation of each test method in the class. | ||
} | ||
|
||
@MainActor | ||
func testExample() throws { | ||
// UI tests must launch the application that they test. | ||
let app = XCUIApplication() | ||
app.launch() | ||
|
||
// Use XCTAssert and related functions to verify your tests produce the correct results. | ||
} | ||
|
||
@MainActor | ||
func testLaunchPerformance() throws { | ||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { | ||
// This measures how long it takes to launch your application. | ||
measure(metrics: [XCTApplicationLaunchMetric()]) { | ||
XCUIApplication().launch() | ||
} | ||
} | ||
} | ||
} |
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,33 @@ | ||
// | ||
// MyAppUITestsLaunchTests.swift | ||
// MyAppUITests | ||
// | ||
// Created by Thomas on 12/3/24. | ||
// | ||
|
||
import XCTest | ||
|
||
final class MyAppUITestsLaunchTests: XCTestCase { | ||
|
||
override class var runsForEachTargetApplicationUIConfiguration: Bool { | ||
true | ||
} | ||
|
||
override func setUpWithError() throws { | ||
continueAfterFailure = false | ||
} | ||
|
||
@MainActor | ||
func testLaunch() throws { | ||
let app = XCUIApplication() | ||
app.launch() | ||
|
||
// Insert steps here to perform after app launch but before taking a screenshot, | ||
// such as logging into a test account or navigating somewhere in the app | ||
|
||
let attachment = XCTAttachment(screenshot: app.screenshot()) | ||
attachment.name = "Launch Screen" | ||
attachment.lifetime = .keepAlways | ||
add(attachment) | ||
} | ||
} |
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,30 @@ | ||
# Combine SwiftUI MVVM Dependency Injection | ||
|
||
A boilerplate demonstrates how to use combine and MVVM in the SwiftUI app. | ||
|
||
# Structure | ||
|
||
ProjectRoot/ | ||
├── Models/ | ||
│ └── User.swift | ||
├── ViewModels/ | ||
│ └── UserViewModel.swift | ||
├── Views/ | ||
│ ├── UserListView.swift | ||
│ └── UserDetailView.swift | ||
└── Services/ | ||
└── UserService.swift | ||
|
||
# Build Tools & Version | ||
|
||
Xcode 15.3 | ||
|
||
iOS 15.6+ | ||
|
||
## Contributing | ||
|
||
We appreciate your interest in contributing to 'Combine SwiftUI MVVM Dependency Injection' . Feel free to open issues or submit pull requests. | ||
|
||
## License | ||
|
||
This project is licensed under the [BSD-4-Clause License](LICENSE). |