Skip to content

Commit f3df1a6

Browse files
committed
Example: notes screen and mock data
1 parent 9ec13d1 commit f3df1a6

File tree

13 files changed

+485
-21
lines changed

13 files changed

+485
-21
lines changed

Example/AppDelegate.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import ServiceContainerKit
1111

1212
@UIApplicationMain
1313
class AppDelegate: UIResponder, UIApplicationDelegate {
14+
15+
private let enableFillMockData = true
1416

1517
var window: UIWindow?
1618
private var appServices: AppDelegateServices?
@@ -22,15 +24,48 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
2224
ServiceInjectResolver.register(services)
2325

2426
// AutoLogin
25-
appServices.userService.auth(login: "User") { result in
27+
appServices.userService.auth(login: "User") { [weak self] result in
2628
print("AutoLogin result: \(result)")
29+
30+
if let self = self, self.enableFillMockData {
31+
self.fillMockData(services: services)
32+
}
2733
}
2834

2935
// Prepare for UI
3036
MainViewController.prepareForMake()
3137

3238
return true
3339
}
40+
41+
private func fillMockData(services: Services) {
42+
let foldersManager = services.folders.manager.getServiceOrFatal()
43+
44+
["Fast notes", "Events", "Common"].forEach { name in
45+
foldersManager.add(content: .init(name: name)) { [weak self] result in
46+
switch result {
47+
case .success(let folder): self?.fillMockNotes(services: services, folder: folder)
48+
case .failure: break
49+
}
50+
}
51+
}
52+
}
53+
54+
private func fillMockNotes(services: Services, folder: NoteFolder) {
55+
let contents: [NoteRecord.Content] = [
56+
.init(title: "First", content: "First example note"),
57+
.init(title: "Second", content: "Second\nNote with details")
58+
]
59+
60+
contents.forEach { content in
61+
let editService = services.notes.editService.getServiceOrFatal(
62+
params: .init(folder: folder, record: nil)
63+
)
64+
editService.apply(content: content) { _ in
65+
_ = editService
66+
}
67+
}
68+
}
3469

3570
func applicationWillResignActive(_ application: UIApplication) {
3671
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.

Example/Presentation/Base.lproj/Main.storyboard

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<dependencies>
55
<deployment identifier="iOS"/>
66
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
7+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
78
<capability name="System colors in document resources" minToolsVersion="11.0"/>
89
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
910
</dependencies>
@@ -48,12 +49,13 @@
4849
</connections>
4950
</tableView>
5051
<navigationItem key="navigationItem" title="Folders" id="xV0-JN-ufi">
52+
<barButtonItem key="backBarButtonItem" title="Folders" id="Fsq-BL-4sn"/>
5153
<barButtonItem key="leftBarButtonItem" image="person.circle" catalog="system" id="lYO-hn-aKN">
5254
<connections>
5355
<action selector="manageUser" destination="uQv-5d-hd3" id="FQK-KE-BTn"/>
5456
</connections>
5557
</barButtonItem>
56-
<barButtonItem key="rightBarButtonItem" title="Item" systemItem="add" id="cDS-TO-5Ne">
58+
<barButtonItem key="rightBarButtonItem" systemItem="add" id="cDS-TO-5Ne">
5759
<connections>
5860
<action selector="addFolder" destination="uQv-5d-hd3" id="0n7-PC-Kh1"/>
5961
</connections>
@@ -65,11 +67,107 @@
6567
<action selector="refresh" destination="uQv-5d-hd3" eventType="valueChanged" id="DoN-M1-d2c"/>
6668
</connections>
6769
</refreshControl>
70+
<connections>
71+
<segue destination="WR2-fQ-bPg" kind="show" identifier="notes" id="eyk-fT-w4F"/>
72+
</connections>
6873
</tableViewController>
6974
<placeholder placeholderIdentifier="IBFirstResponder" id="JuM-GR-pYU" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
7075
</objects>
7176
<point key="canvasLocation" x="394" y="730"/>
7277
</scene>
78+
<!--Notes-->
79+
<scene sceneID="sL4-9e-j8H">
80+
<objects>
81+
<tableViewController id="WR2-fQ-bPg" customClass="NotesViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
82+
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Kjb-mn-huE">
83+
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
84+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
85+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
86+
<prototypes>
87+
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cell" textLabel="sGB-av-7p4" detailTextLabel="AJH-O5-nrQ" style="IBUITableViewCellStyleSubtitle" id="UUE-tV-Yp7">
88+
<rect key="frame" x="0.0" y="28" width="414" height="55.5"/>
89+
<autoresizingMask key="autoresizingMask"/>
90+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="UUE-tV-Yp7" id="o2m-QP-PlT">
91+
<rect key="frame" x="0.0" y="0.0" width="383" height="55.5"/>
92+
<autoresizingMask key="autoresizingMask"/>
93+
<subviews>
94+
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="sGB-av-7p4">
95+
<rect key="frame" x="20" y="10" width="33" height="20.5"/>
96+
<autoresizingMask key="autoresizingMask"/>
97+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
98+
<nil key="textColor"/>
99+
<nil key="highlightedColor"/>
100+
</label>
101+
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="AJH-O5-nrQ">
102+
<rect key="frame" x="20" y="31.5" width="44" height="14.5"/>
103+
<autoresizingMask key="autoresizingMask"/>
104+
<fontDescription key="fontDescription" type="system" pointSize="12"/>
105+
<nil key="textColor"/>
106+
<nil key="highlightedColor"/>
107+
</label>
108+
</subviews>
109+
</tableViewCellContentView>
110+
</tableViewCell>
111+
</prototypes>
112+
<connections>
113+
<outlet property="dataSource" destination="WR2-fQ-bPg" id="41G-gK-Pt3"/>
114+
<outlet property="delegate" destination="WR2-fQ-bPg" id="BME-G7-BgJ"/>
115+
</connections>
116+
</tableView>
117+
<navigationItem key="navigationItem" title="Notes" largeTitleDisplayMode="never" id="yci-Td-pN4">
118+
<barButtonItem key="backBarButtonItem" title="Notes" id="XMY-yp-ucX"/>
119+
<barButtonItem key="rightBarButtonItem" systemItem="add" id="DWq-Xn-yT6">
120+
<connections>
121+
<segue destination="7Zx-7n-AfI" kind="presentation" identifier="add" id="TcI-y7-fhw"/>
122+
</connections>
123+
</barButtonItem>
124+
</navigationItem>
125+
<refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="B0w-RP-N7Z">
126+
<autoresizingMask key="autoresizingMask"/>
127+
<connections>
128+
<action selector="refresh" destination="WR2-fQ-bPg" eventType="valueChanged" id="ZRw-nw-kC6"/>
129+
</connections>
130+
</refreshControl>
131+
<connections>
132+
<segue destination="7Zx-7n-AfI" kind="presentation" identifier="edit" id="DtS-ot-qGZ"/>
133+
</connections>
134+
</tableViewController>
135+
<placeholder placeholderIdentifier="IBFirstResponder" id="cUr-yh-hzx" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
136+
</objects>
137+
<point key="canvasLocation" x="1346" y="730"/>
138+
</scene>
139+
<!--Navigation Controller-->
140+
<scene sceneID="r3j-sO-9t7">
141+
<objects>
142+
<navigationController id="7Zx-7n-AfI" sceneMemberID="viewController">
143+
<navigationBar key="navigationBar" contentMode="scaleToFill" id="uVq-EC-qQx">
144+
<rect key="frame" x="0.0" y="0.0" width="414" height="56"/>
145+
<autoresizingMask key="autoresizingMask"/>
146+
</navigationBar>
147+
<connections>
148+
<segue destination="wbC-kD-tpp" kind="relationship" relationship="rootViewController" id="WGR-af-W1R"/>
149+
</connections>
150+
</navigationController>
151+
<placeholder placeholderIdentifier="IBFirstResponder" id="Pcw-Ac-oTZ" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
152+
</objects>
153+
<point key="canvasLocation" x="2368" y="730"/>
154+
</scene>
155+
<!--Note-->
156+
<scene sceneID="fck-ns-gca">
157+
<objects>
158+
<viewController id="wbC-kD-tpp" customClass="NoteEditViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
159+
<view key="view" contentMode="scaleToFill" id="Dqy-OV-IFM">
160+
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
161+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
162+
<viewLayoutGuide key="safeArea" id="PAV-oK-u9U"/>
163+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
164+
</view>
165+
<navigationItem key="navigationItem" title="Note" id="Zja-3p-t35"/>
166+
</viewController>
167+
<placeholder placeholderIdentifier="IBFirstResponder" id="0HS-2z-SOG" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
168+
</objects>
169+
<point key="canvasLocation" x="3325" y="730"/>
170+
</scene>
73171
<!--Navigation Controller-->
74172
<scene sceneID="atc-EO-pgX">
75173
<objects>
@@ -87,6 +185,9 @@
87185
<point key="canvasLocation" x="-499" y="730"/>
88186
</scene>
89187
</scenes>
188+
<inferredMetricsTieBreakers>
189+
<segue reference="TcI-y7-fhw"/>
190+
</inferredMetricsTieBreakers>
90191
<resources>
91192
<image name="person.circle" catalog="system" width="128" height="121"/>
92193
<systemColor name="systemBackgroundColor">

Example/Presentation/Main/MainPresenter.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,10 @@ final class MainPresenterImpl: MainPresenter {
6262
self.showAlert = showAlertHandler
6363
self.routeToFolder = routeToFolderHandler
6464

65-
foldersManager.foldersPublisher.map { [weak self] in
66-
guard let self = self else { return [] }
67-
return $0.map { self.buildCell(folder: $0) }
68-
}.assign(to: \Self.models, on: self)
69-
.store(in: &cancellableSet)
65+
foldersManager.foldersPublisher.sink { [weak self] in
66+
guard let self = self else { return }
67+
self.models = $0.map { self.buildCell(folder: $0) }
68+
}.store(in: &cancellableSet)
7069
}
7170

7271
func login(user: String) {
@@ -106,7 +105,7 @@ final class MainPresenterImpl: MainPresenter {
106105
showAlert(title, message)
107106
}
108107

109-
private func deleteFolder(folder: NoteFolder) {
108+
private func deleteFolder(_ folder: NoteFolder) {
110109
foldersManager.remove(folderId: folder.id) { [weak self] result in
111110
switch result {
112111
case .success: break
@@ -123,7 +122,7 @@ final class MainPresenterImpl: MainPresenter {
123122
text: folder.content.name,
124123
detail: nil,
125124
onSelected: { [weak self] in self?.routeToFolder(folder) },
126-
onDeleted: { [weak self] in self?.deleteFolder(folder: folder) }
125+
onDeleted: { [weak self] in self?.deleteFolder(folder) }
127126
)
128127
}
129128
}

Example/Presentation/Main/MainViewController.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,24 @@ extension MainViewController {
1818
}
1919

2020
class MainViewController: SimpleTableViewController {
21-
@EntityInject(MainPresenter.self) var presenter
21+
@EntityInject(MainPresenter.self)
22+
private var presenter
2223

23-
var cancellableSet: Set<AnyCancellable> = []
24+
private var cancellableSet: Set<AnyCancellable> = []
2425

2526
override func viewDidLoad() {
2627
super.viewDidLoad()
2728

29+
adapter.autoDeselect = false
30+
2831
presenter.configure(
2932
showAlertHandler: { [weak self] title, message in
3033
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
3134
alert.addAction(.init(title: "OK", style: .default, handler: nil))
3235
self?.present(alert, animated: true, completion: nil)
3336
},
34-
routeToFolderHandler: { folder in
35-
print("Routed to \(folder.id)")
37+
routeToFolderHandler: { [weak self] folder in
38+
self?.routeTo(folder: folder)
3639
}
3740
)
3841
presenter.titlePublisher.sink { [weak self] in
@@ -96,14 +99,14 @@ class MainViewController: SimpleTableViewController {
9699
present(alert, animated: true, completion: nil)
97100
}
98101

99-
/*
100102
// MARK: - Navigation
101-
102-
// In a storyboard-based application, you will often want to do a little preparation before navigation
103-
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
104-
// Get the new view controller using segue.destination.
105-
// Pass the selected object to the new view controller.
103+
private enum SegueIdentifier: String {
104+
case notes
105+
}
106+
107+
private func routeTo(folder: NoteFolder) {
108+
NotesViewController.prepareForMake(folder: folder)
109+
performSegue(withIdentifier: SegueIdentifier.notes.rawValue, sender: nil)
106110
}
107-
*/
108111

109112
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// NoteEditPresenter.swift
3+
// Example
4+
//
5+
// Created by Виталий Короткий on 02.01.2021.
6+
// Copyright © 2021 ProVir. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Combine
11+
12+
protocol NoteEditPresenter: class {
13+
var titlePublisher: AnyPublisher<String, Never> { get }
14+
}
15+
16+
final class NoteEditPresenterImpl: NoteEditPresenter {
17+
private let editService: NoteRecordEditService
18+
19+
var titlePublisher: AnyPublisher<String, Never> {
20+
editService.recordPublisher.map {
21+
$0 != nil ? "Edit note" : "Add note"
22+
}.eraseToAnyPublisher()
23+
}
24+
25+
init(editService: NoteRecordEditService) {
26+
self.editService = editService
27+
}
28+
29+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// NoteEditViewController.swift
3+
// Example
4+
//
5+
// Created by Виталий Короткий on 02.01.2021.
6+
// Copyright © 2021 ProVir. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import Combine
11+
import ServiceContainerKit
12+
13+
class NoteEditViewController: UIViewController {
14+
@EntityInject(NoteEditPresenter.self)
15+
private var presenter
16+
17+
private var cancellableSet: Set<AnyCancellable> = []
18+
19+
override func viewDidLoad() {
20+
super.viewDidLoad()
21+
22+
presenter.titlePublisher.sink { [weak self] in
23+
self?.navigationItem.title = $0
24+
}.store(in: &cancellableSet)
25+
}
26+
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// NoteEditViewControllerFactory.swift
3+
// Example
4+
//
5+
// Created by Виталий Короткий on 02.01.2021.
6+
// Copyright © 2021 ProVir. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import ServiceContainerKit
11+
12+
extension NoteEditViewController {
13+
private struct Dependencies {
14+
@ServiceParamsInject(\Services.notes.editService) var editService
15+
16+
init(folder: NoteFolder, editRecord: NoteRecord?) {
17+
$editService.setParameters(.init(folder: folder, record: editRecord))
18+
}
19+
}
20+
21+
static func prepareForMakeNew(folder: NoteFolder) {
22+
prepareForMake(use: .init(folder: folder, editRecord: nil))
23+
}
24+
25+
static func prepareForMakeEdit(folder: NoteFolder, record: NoteRecord) {
26+
prepareForMake(use: .init(folder: folder, editRecord: record))
27+
}
28+
29+
private static func prepareForMake(use dependencies: Dependencies) {
30+
let presenter = NoteEditPresenterImpl(editService: dependencies.editService)
31+
EntityInjectResolver.registerForFirstInject(presenter)
32+
}
33+
}

0 commit comments

Comments
 (0)