Skip to content

Commit 4c8e443

Browse files
committed
feat: Example app
1 parent 77412e8 commit 4c8e443

File tree

93 files changed

+2411
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+2411
-0
lines changed

Example/App/AppDelegate.swift

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// AppDelegate.swift
3+
// InStoreApp
4+
//
5+
// Created by Jakob Mygind on 15/11/2021.
6+
//
7+
8+
import AppFeature
9+
import Combine
10+
import SwiftUI
11+
import UserNotificationsClient
12+
13+
@main
14+
final class AppDelegate: NSObject, UIApplicationDelegate {
15+
func application(
16+
_ application: UIApplication,
17+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
18+
) -> Bool {
19+
return true
20+
}
21+
}
22+
23+
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
24+
var window: UIWindow?
25+
var userClient: UserNotificationClient?
26+
27+
func scene(
28+
_ scene: UIScene,
29+
willConnectTo session: UISceneSession,
30+
options connectionOptions: UIScene.ConnectionOptions
31+
) {
32+
guard let scene = (scene as? UIWindowScene) else { return }
33+
self.window = UIWindow(windowScene: scene)
34+
self.startApp()
35+
}
36+
}
37+
38+
// MARK: - Dependencies setup
39+
40+
extension SceneDelegate {
41+
fileprivate func startApp() {
42+
// Set the user and remote notifications clients
43+
// The user notification client needs to be initialized here at the app start
44+
// to assign the UNNotificationCenter delegate soon enough to react to events
45+
// coming from the notifications that opened the app
46+
let environment = AppEnvironment(remoteNotificationsClient: .live,
47+
userNotificationsClient: .live())
48+
49+
let vm = AppViewModel(environment: environment)
50+
let appView = AppView(viewModel: vm)
51+
52+
// Listen to the notification events and handle them
53+
Task {
54+
for await event in environment.userNotificationsClient.delegate() {
55+
handleNotificationEvent(event, appViewModel: vm)
56+
}
57+
}
58+
59+
// Register for remote notifications if the user granted the permissions
60+
Task {
61+
let allowed = await (environment.userNotificationsClient.getAuthorizationStatus() == .authorized)
62+
if allowed {
63+
environment.remoteNotificationsClient.registerForRemoteNotifications()
64+
}
65+
}
66+
67+
self.window?.rootViewController = UIHostingController(rootView: appView)
68+
self.window?.makeKeyAndVisible()
69+
}
70+
71+
/// Handles the incoming notification events
72+
/// - Parameters:
73+
/// - event: Notification event. They match the UNNotificationCenterDelegate methods
74+
/// - appViewModel:AppViewModel to handle the notification events
75+
func handleNotificationEvent(_ event: UserNotificationClient.DelegateEvent,
76+
appViewModel: AppViewModel) {
77+
switch event {
78+
case .willPresentNotification(_, let completion):
79+
// Notification presented when the app is in FOREGROUND
80+
// Decide how to present it depending on the context
81+
// Pass the presentation options to the completion
82+
// If you do not pass anythig, the notification will not be presented
83+
completion([.banner, .sound, .list, .badge])
84+
case .didReceiveResponse(let response, let completion):
85+
// User tapped on the notification
86+
// Is triggered both when the app is in foreground and background
87+
88+
// Read the user info
89+
if let deeplink = response.notification.request.content.userInfo["deeplink"] as? String {
90+
appViewModel.receiveNotificationMessage(deeplink)
91+
}
92+
93+
// Make sure to always run the completion
94+
completion()
95+
return
96+
case .openSettingsForNotification:
97+
return
98+
}
99+
}
100+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"colors" : [
3+
{
4+
"idiom" : "universal"
5+
}
6+
],
7+
"info" : {
8+
"author" : "xcode",
9+
"version" : 1
10+
}
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "[email protected]",
5+
"idiom" : "universal",
6+
"platform" : "ios",
7+
"size" : "1024x1024"
8+
}
9+
],
10+
"info" : {
11+
"author" : "xcode",
12+
"version" : 1
13+
}
14+
}
80.7 KB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"author" : "xcode",
4+
"version" : 1
5+
}
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"images" : [
3+
{
4+
"idiom" : "universal",
5+
"scale" : "1x"
6+
},
7+
{
8+
"idiom" : "universal",
9+
"scale" : "2x"
10+
},
11+
{
12+
"idiom" : "universal",
13+
"scale" : "3x"
14+
}
15+
],
16+
"info" : {
17+
"author" : "xcode",
18+
"version" : 1
19+
}
20+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3+
<device id="retina6_12" orientation="portrait" appearance="light"/>
4+
<dependencies>
5+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
6+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
7+
<capability name="System colors in document resources" minToolsVersion="11.0"/>
8+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+
</dependencies>
10+
<scenes>
11+
<!--View Controller-->
12+
<scene sceneID="EHf-IW-A2E">
13+
<objects>
14+
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
15+
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
16+
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
17+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
18+
<subviews>
19+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Hold On" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="G8r-KV-W15">
20+
<rect key="frame" x="165" y="416" width="63" height="21"/>
21+
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
22+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
23+
<nil key="textColor"/>
24+
<nil key="highlightedColor"/>
25+
</label>
26+
</subviews>
27+
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
28+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
29+
</view>
30+
</viewController>
31+
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
32+
</objects>
33+
<point key="canvasLocation" x="53" y="375"/>
34+
</scene>
35+
</scenes>
36+
<resources>
37+
<systemColor name="systemBackgroundColor">
38+
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
39+
</systemColor>
40+
</resources>
41+
</document>

Example/App/Info.plist

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>API_BASE_URL_DEV</key>
6+
<string>$(API_BASE_URL_DEV)</string>
7+
<key>API_BASE_URL_PROD</key>
8+
<string>$(API_BASE_URL_PROD)</string>
9+
<key>DEFAULT_BASE_URL</key>
10+
<string>$(DEFAULT_BASE_URL)</string>
11+
<key>ITSAppUsesNonExemptEncryption</key>
12+
<false/>
13+
<key>UIApplicationSceneManifest</key>
14+
<dict>
15+
<key>UIApplicationSupportsMultipleScenes</key>
16+
<true/>
17+
<key>UISceneConfigurations</key>
18+
<dict>
19+
<key>UIWindowSceneSessionRoleApplication</key>
20+
<array>
21+
<dict>
22+
<key>UISceneConfigurationName</key>
23+
<string>Default Configuration</string>
24+
<key>UISceneDelegateClassName</key>
25+
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
26+
</dict>
27+
</array>
28+
</dict>
29+
</dict>
30+
<key>UIStatusBarStyle</key>
31+
<string>UIStatusBarStyleLightContent</string>
32+
<key>UISupportedExternalAccessoryProtocols</key>
33+
<array>
34+
<string>com.bixolon.protocol</string>
35+
</array>
36+
<key>UIViewControllerBasedStatusBarAppearance</key>
37+
<false/>
38+
</dict>
39+
</plist>

Example/Modules/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1320"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "APIClient"
18+
BuildableName = "APIClient"
19+
BlueprintName = "APIClient"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Debug"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
</LaunchAction>
44+
<ProfileAction
45+
buildConfiguration = "Release"
46+
shouldUseLaunchSchemeArgsEnv = "YES"
47+
savedToolIdentifier = ""
48+
useCustomWorkingDirectory = "NO"
49+
debugDocumentVersioning = "YES">
50+
<MacroExpansion>
51+
<BuildableReference
52+
BuildableIdentifier = "primary"
53+
BlueprintIdentifier = "APIClient"
54+
BuildableName = "APIClient"
55+
BlueprintName = "APIClient"
56+
ReferencedContainer = "container:">
57+
</BuildableReference>
58+
</MacroExpansion>
59+
</ProfileAction>
60+
<AnalyzeAction
61+
buildConfiguration = "Debug">
62+
</AnalyzeAction>
63+
<ArchiveAction
64+
buildConfiguration = "Release"
65+
revealArchiveInOrganizer = "YES">
66+
</ArchiveAction>
67+
</Scheme>

0 commit comments

Comments
 (0)