├── .github
└── images
│ ├── frame
│ ├── dark_keyboard.png
│ ├── dark_main.png
│ ├── dark_setting.png
│ ├── white_keyboard.png
│ ├── white_main.png
│ └── white_setting.png
│ ├── header.png
│ ├── no_frame
│ ├── dark_keyboard.png
│ ├── dark_main.png
│ ├── dark_setting.png
│ ├── white_keyboard.png
│ ├── white_main.png
│ └── white_setting.png
│ └── preview.png
├── .gitignore
├── LICENSE
├── Podfile
├── Podfile.lock
├── README.md
├── keyboard
├── BaseInputViewController.swift
├── Extensions
│ └── UIButton.swift
├── Info.plist
├── KeyboardViewController.swift
├── KeyboardViewReactor.swift
├── Sections
│ └── ListSection.swift
├── Views
│ ├── ListCell.swift
│ └── ListCellReactor.swift
├── en.lproj
│ └── InfoPlist.strings
├── keyboard.entitlements
└── ko.lproj
│ └── InfoPlist.strings
├── reactorkitKeyboardExample.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── fernando.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcshareddata
│ └── xcschemes
│ │ ├── keyboard.xcscheme
│ │ └── reactorkitKeyboardExample.xcscheme
└── xcuserdata
│ └── fernando.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── reactorkitKeyboardExample.xcworkspace
├── contents.xcworkspacedata
├── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ └── fernando.xcuserdatad
│ ├── UserInterfaceState.xcuserstate
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
└── reactorkitKeyboardExample
├── AppDelegate.swift
├── Base.lproj
├── LaunchScreen.storyboard
└── Main.storyboard
├── Base
├── BaseNavigationController.swift
├── BaseTableViewCell.swift
└── BaseViewController.swift
├── Common
├── Constants.swift
├── GlobalColors.swift
├── UIColor.swift
└── Utillity.swift
├── Extensions
└── Rx
│ └── UITableView+Rx.swift
├── Info.plist
├── Logging
└── Logger.swift
├── Sections
├── MainSection.swift
└── SettingSection.swift
├── Supported Files
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ ├── Icon-App-83.5x83.5@2x.png
│ │ └── ItunesArtwork@2x.png
│ ├── Contents.json
│ ├── clipboard.imageset
│ │ ├── Contents.json
│ │ ├── clipboard@1x-1.png
│ │ ├── clipboard@1x.png
│ │ ├── clipboard@2x-1.png
│ │ ├── clipboard@2x.png
│ │ ├── clipboard@3x-1.png
│ │ └── clipboard@3x.png
│ ├── delete.imageset
│ │ ├── Contents.json
│ │ ├── delete@1x.png
│ │ ├── delete@2x.png
│ │ ├── delete@3x.png
│ │ ├── delete_white@1x.png
│ │ ├── delete_white@2x.png
│ │ └── delete_white@3x.png
│ ├── global.imageset
│ │ ├── Contents.json
│ │ ├── global-white@1x.png
│ │ ├── global-white@2x.png
│ │ ├── global-white@3x.png
│ │ ├── global@1x.png
│ │ ├── global@2x.png
│ │ └── global@3x.png
│ ├── plus.imageset
│ │ ├── Contents.json
│ │ ├── plus.png
│ │ ├── plus@2x.png
│ │ └── plus@3x.png
│ └── return.imageset
│ │ ├── Contents.json
│ │ ├── return-white@1x.png
│ │ ├── return-white@2x.png
│ │ ├── return-white@3x.png
│ │ ├── return@1x.png
│ │ ├── return@2x.png
│ │ └── return@3x.png
├── en.lproj
│ ├── InfoPlist.strings
│ └── Localizable.strings
└── ko.lproj
│ ├── InfoPlist.strings
│ └── Localizable.strings
├── Types
├── SettingFooterType.swift
└── SettingMenuTypes.swift
├── ViewController.swift
├── ViewControllers
├── MainViewController.swift
├── MainViewReactor.swift
├── SettingsViewController.swift
├── SettingsViewReactor.swift
├── WriteViewController.swift
└── WriteViewReactor.swift
├── Views
└── Cells
│ ├── MainTableViewCell.swift
│ ├── MainTableViewCellReactor.swift
│ ├── SettingCell.swift
│ ├── SettingCellReactor.swift
│ ├── SettingSectionFooterView.swift
│ └── SettingSectionFooterViewReactor.swift
├── ko.lproj
├── LaunchScreen.strings
└── Main.strings
└── reactorkitKeyboardExample.entitlements
/.github/images/frame/dark_keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/dark_keyboard.png
--------------------------------------------------------------------------------
/.github/images/frame/dark_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/dark_main.png
--------------------------------------------------------------------------------
/.github/images/frame/dark_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/dark_setting.png
--------------------------------------------------------------------------------
/.github/images/frame/white_keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/white_keyboard.png
--------------------------------------------------------------------------------
/.github/images/frame/white_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/white_main.png
--------------------------------------------------------------------------------
/.github/images/frame/white_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/frame/white_setting.png
--------------------------------------------------------------------------------
/.github/images/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/header.png
--------------------------------------------------------------------------------
/.github/images/no_frame/dark_keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/dark_keyboard.png
--------------------------------------------------------------------------------
/.github/images/no_frame/dark_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/dark_main.png
--------------------------------------------------------------------------------
/.github/images/no_frame/dark_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/dark_setting.png
--------------------------------------------------------------------------------
/.github/images/no_frame/white_keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/white_keyboard.png
--------------------------------------------------------------------------------
/.github/images/no_frame/white_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/white_main.png
--------------------------------------------------------------------------------
/.github/images/no_frame/white_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/no_frame/white_setting.png
--------------------------------------------------------------------------------
/.github/images/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/.github/images/preview.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Pods/
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Fernando.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '11.0'
3 |
4 | target 'reactorkitKeyboardExample' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 | inhibit_all_warnings!
8 | # Pods for reactorkitKeyboardExample
9 |
10 | # Architecture
11 | pod 'ReactorKit'
12 |
13 | # UI
14 | pod 'Then'
15 | pod 'SnapKit'
16 | pod 'ReusableKit'
17 | pod 'AcknowList'
18 |
19 | # Rx
20 | pod 'RxSwift'
21 | pod 'RxCocoa'
22 | pod 'RxViewController'
23 | pod 'RxDataSources'
24 | pod 'RxOptional'
25 |
26 | # Logging
27 | pod 'CocoaLumberjack/Swift'
28 |
29 | target 'keyboard' do
30 | inherit! :search_paths
31 | end
32 |
33 | end
34 | # Uncomment the next line to define a global platform for your project
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AcknowList (1.9.4)
3 | - CocoaLumberjack/Core (3.6.1)
4 | - CocoaLumberjack/Swift (3.6.1):
5 | - CocoaLumberjack/Core
6 | - Differentiator (4.0.1)
7 | - ReactorKit (2.0.1):
8 | - RxSwift (~> 5.0)
9 | - ReusableKit (3.0.0):
10 | - ReusableKit/Core (= 3.0.0)
11 | - ReusableKit/Core (3.0.0)
12 | - RxCocoa (5.1.1):
13 | - RxRelay (~> 5)
14 | - RxSwift (~> 5)
15 | - RxDataSources (4.0.1):
16 | - Differentiator (~> 4.0)
17 | - RxCocoa (~> 5.0)
18 | - RxSwift (~> 5.0)
19 | - RxOptional (4.1.0):
20 | - RxCocoa (~> 5)
21 | - RxSwift (~> 5)
22 | - RxRelay (5.1.1):
23 | - RxSwift (~> 5)
24 | - RxSwift (5.1.1)
25 | - RxViewController (1.0.0):
26 | - RxCocoa (~> 5.0)
27 | - RxSwift (~> 5.0)
28 | - SnapKit (5.0.1)
29 | - Then (2.6.0)
30 |
31 | DEPENDENCIES:
32 | - AcknowList
33 | - CocoaLumberjack/Swift
34 | - ReactorKit
35 | - ReusableKit
36 | - RxCocoa
37 | - RxDataSources
38 | - RxOptional
39 | - RxSwift
40 | - RxViewController
41 | - SnapKit
42 | - Then
43 |
44 | SPEC REPOS:
45 | trunk:
46 | - AcknowList
47 | - CocoaLumberjack
48 | - Differentiator
49 | - ReactorKit
50 | - ReusableKit
51 | - RxCocoa
52 | - RxDataSources
53 | - RxOptional
54 | - RxRelay
55 | - RxSwift
56 | - RxViewController
57 | - SnapKit
58 | - Then
59 |
60 | SPEC CHECKSUMS:
61 | AcknowList: a236060b8c33141d7756814fd21d5dab477fc193
62 | CocoaLumberjack: b17ae15142558d08bbacf69775fa10c4abbebcc9
63 | Differentiator: 886080237d9f87f322641dedbc5be257061b0602
64 | ReactorKit: a63c5e11e0fd32d59d672e54178b0ed2876b764b
65 | ReusableKit: e5f853ad4652e411f96b6119b2488afa12929be6
66 | RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601
67 | RxDataSources: efee07fa4de48477eca0a4611e6d11e2da9c1114
68 | RxOptional: b1fcd60856807a564c0215c2184b8d33e7826dc2
69 | RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9
70 | RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178
71 | RxViewController: 7330a46e5c31cd680db169da4c9fc8676e975a81
72 | SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
73 | Then: 90cd104fd951cec1980a03f57704ad8f784d4d79
74 |
75 | PODFILE CHECKSUM: fc1e5314b28d12c4e3b6c442f6ed724bc66eb1ef
76 |
77 | COCOAPODS: 1.8.4
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Reactorkit-keyboard-example [](#)
4 |
5 | This project is ReactorKit based keyboard aplication example.
6 |
7 | # 🐒 Features
8 | - 🚀 ReactorKit based.
9 | - 🎉 iOS13 Dark mode support.
10 | - ➕ Using cocoapods
11 |
12 | # Quick Start
13 |
14 | 
15 |
16 | # 📚 Skills
17 |
18 | - Architecture
19 |
20 | - [ReactorKit](https://github.com/ReactorKit/ReactorKit)
21 |
22 | - Reactive
23 |
24 | - [RxSwift](https://github.com/ReactiveX/RxSwift)
25 | - [RxDataSources](https://github.com/RxSwiftCommunity/RxDataSources)
26 | - [RxOptional](https://github.com/RxSwiftCommunity/RxOptional)
27 |
28 | - UI
29 |
30 | - [SnapKit](https://github.com/SnapKit/SnapKit)
31 |
32 | - etc
33 | - [AcknowList](https://github.com/vtourraine/AcknowList)
34 |
35 | # ❤️ Contributing
36 | This is an open source project, so feel free to contribute. How?
37 |
38 | - Open an issue.
39 | - Send feedback via email.
40 | - Propose your own fixes, suggestions and open a pull request with the changes.
41 |
--------------------------------------------------------------------------------
/keyboard/BaseInputViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseInputViewController.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class BaseInputViewController: UIInputViewController {
13 |
14 | var disposeBag = DisposeBag()
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 |
19 | // Do any additional setup after loading the view.
20 | self.addViews()
21 | self.updateViewConstraints()
22 | }
23 |
24 | override func updateViewConstraints() {
25 | super.updateViewConstraints()
26 | print("updateViewConstraints")
27 | }
28 |
29 | func addViews() {
30 | print("addViews")
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/keyboard/Extensions/UIButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIButton {
12 | func setBackgroundColor(_ color: UIColor, for state: UIControl.State) {
13 | UIGraphicsBeginImageContext(CGSize(width: 1.0, height: 1.0))
14 | guard let context = UIGraphicsGetCurrentContext() else { return }
15 | context.setFillColor(color.cgColor)
16 | context.fill(CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0))
17 |
18 | let backgroundImage = UIGraphicsGetImageFromCurrentImageContext()
19 | UIGraphicsEndImageContext()
20 |
21 | self.setBackgroundImage(backgroundImage, for: state)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/keyboard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | keyboard
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 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | IsASCIICapable
28 |
29 | PrefersRightToLeft
30 |
31 | PrimaryLanguage
32 | en-US
33 | RequestsOpenAccess
34 |
35 |
36 | NSExtensionPointIdentifier
37 | com.apple.keyboard-service
38 | NSExtensionPrincipalClass
39 | $(PRODUCT_MODULE_NAME).KeyboardViewController
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/keyboard/KeyboardViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyboardViewController.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SnapKit
11 | import Then
12 | import RxSwift
13 | import RxCocoa
14 | import ReusableKit
15 | import ReactorKit
16 | import RxDataSources
17 | import RxViewController
18 |
19 | class KeyboardViewController: BaseInputViewController, ReactorKit.View {
20 |
21 | typealias Reactor = KeyboardViewReactor
22 |
23 | @IBOutlet var nextKeyboardButton: UIButton!
24 |
25 | private struct Metric {
26 | static let bottomButtonWidth: CGFloat = 80.0
27 | static let globalButtonWidth: CGFloat = 60.0
28 | static let deleteButtonWidth: CGFloat = 60.0
29 | static let enterButtonWidth: CGFloat = 80.0
30 | static let bottomButtonHeight: CGFloat = 45.0
31 | static let spaceButtonWidth: CGFloat = 100.0
32 | static let marginButtonLeftRight: CGFloat = 4.0
33 | static let buttonCornerRadius: CGFloat = 8.0
34 |
35 | static let tableViewCellHeight: CGFloat = 40.0
36 | static let tableViewHeight: CGFloat = 200.0
37 | static let textSize: CGFloat = 15.0
38 |
39 | static let emptyImageWidthHeight: CGFloat = 128.0
40 | static let emptyMessageTop: CGFloat = 20.0
41 | static let emptyMessageSize: CGFloat = 14.0
42 | }
43 |
44 | private struct Localized {
45 | static let space = NSLocalizedString("space", comment: "스페이스바")
46 | static let emptyMessage = NSLocalizedString("message_list_empty", comment: "등록된 내용이 없습니다")
47 | }
48 |
49 | private struct Reusable {
50 | static let listCell = ReusableCell()
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | super.init(coder: coder)
55 | }
56 |
57 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
58 | defer { self.reactor = KeyboardViewReactor() }
59 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
60 | self.dataSource = self.dataSourceFactory()
61 | }
62 |
63 | private var dataSource: RxTableViewSectionedReloadDataSource?
64 |
65 | private let tableView = UITableView().then {
66 | $0.backgroundColor = Color.keyboardBackground
67 | $0.rowHeight = Metric.tableViewCellHeight
68 | $0.tableHeaderView = UIView(frame: .zero)
69 | $0.tableFooterView = UIView(frame: .zero)
70 | $0.bounces = false
71 |
72 | if #available(iOS 11.0, *) {
73 | $0.contentInsetAdjustmentBehavior = .never
74 | }
75 |
76 | $0.register(Reusable.listCell)
77 | $0.separatorStyle = .singleLine
78 | $0.separatorInset.left = 0
79 | }
80 |
81 | private let bottomWrapView = UIView().then {
82 | $0.backgroundColor = Color.keyboardBackground
83 | }
84 |
85 | private let emptyView = UIView().then {
86 | $0.backgroundColor = Color.keyboardBackground
87 | $0.isHidden = true
88 | }
89 |
90 | private let emptyImageView = UIImageView().then {
91 | $0.image = #imageLiteral(resourceName: "clipboard")
92 | }
93 |
94 | private let emptyMessageLabel = UILabel().then {
95 | $0.text = Localized.emptyMessage
96 | $0.font = UIFont.systemFont(ofSize: Metric.emptyMessageSize)
97 | $0.textColor = Color.description
98 | $0.sizeToFit()
99 | }
100 |
101 | private let globalButton = UIButton().then {
102 | $0.layer.borderWidth = 0.3
103 | $0.layer.borderColor = UIColor.gray.cgColor
104 | $0.layer.masksToBounds = true
105 | $0.layer.cornerRadius = Metric.buttonCornerRadius
106 | $0.setImage(#imageLiteral(resourceName: "global"), for: .normal)
107 | $0.setBackgroundColor(Color.keyBackground, for: .normal)
108 | }
109 |
110 | private let spaceButton = UIButton().then {
111 | $0.layer.borderWidth = 0.3
112 | $0.layer.borderColor = UIColor.gray.cgColor
113 | $0.layer.masksToBounds = true
114 | $0.layer.cornerRadius = Metric.buttonCornerRadius
115 | $0.setTitle(Localized.space, for: .normal)
116 | $0.titleLabel?.font = UIFont.systemFont(ofSize: Metric.textSize)
117 | $0.setTitleColor(Color.title, for:.normal)
118 | $0.setBackgroundColor(Color.keySpaceBackground, for: .normal)
119 | }
120 |
121 | private let deleteButton = UIButton().then {
122 | $0.layer.borderWidth = 0.3
123 | $0.layer.borderColor = UIColor.gray.cgColor
124 | $0.layer.masksToBounds = true
125 | $0.layer.cornerRadius = Metric.buttonCornerRadius
126 | $0.setImage(#imageLiteral(resourceName: "delete"), for: .normal)
127 | $0.setBackgroundColor(Color.keyBackground, for: .normal)
128 | }
129 |
130 | private let enterButton = UIButton().then {
131 | $0.layer.borderWidth = 0.3
132 | $0.layer.borderColor = UIColor.gray.cgColor
133 | $0.layer.masksToBounds = true
134 | $0.layer.cornerRadius = Metric.buttonCornerRadius
135 | $0.setImage(#imageLiteral(resourceName: "return"), for: .normal)
136 | $0.setBackgroundColor(Color.keyBackground, for: .normal)
137 | }
138 |
139 | override func viewDidLoad() {
140 | super.viewDidLoad()
141 | }
142 |
143 | override func addViews() {
144 | super.addViews()
145 |
146 | if needsInputModeSwitchKey {
147 | self.bottomWrapView.addSubview(globalButton)
148 | }
149 |
150 | self.bottomWrapView.addSubview(spaceButton)
151 | self.bottomWrapView.addSubview(deleteButton)
152 | self.bottomWrapView.addSubview(enterButton)
153 |
154 | self.emptyView.addSubview(emptyImageView)
155 | self.emptyView.addSubview(emptyMessageLabel)
156 |
157 | self.view.addSubview(bottomWrapView)
158 | self.view.addSubview(tableView)
159 | self.view.addSubview(emptyView)
160 | }
161 |
162 | override func updateViewConstraints() {
163 | super.updateViewConstraints()
164 |
165 | self.view.snp.makeConstraints { make in
166 | make.height.equalTo(Metric.bottomButtonHeight + Metric.tableViewHeight)
167 | make.width.equalTo(UIScreen.main.bounds.width)
168 | }
169 |
170 | bottomWrapView.snp.makeConstraints { (make) in
171 | make.left.right.bottom.equalToSuperview()
172 | make.height.equalTo(Metric.bottomButtonHeight)
173 | }
174 |
175 | tableView.snp.makeConstraints { (make) in
176 | make.left.right.top.equalToSuperview()
177 | make.bottom.equalTo(bottomWrapView.snp.top)
178 | }
179 |
180 | emptyView.snp.makeConstraints { (make) in
181 | make.left.right.top.equalToSuperview()
182 | make.bottom.equalTo(bottomWrapView.snp.top)
183 | }
184 |
185 | emptyImageView.snp.makeConstraints { (make) in
186 | make.center.equalToSuperview()
187 | }
188 |
189 | emptyMessageLabel.snp.makeConstraints { (make) in
190 | make.top.equalTo(emptyImageView.snp.bottom).offset(Metric.emptyMessageTop)
191 | make.centerX.equalToSuperview()
192 | }
193 |
194 | if needsInputModeSwitchKey {
195 | globalButton.snp.makeConstraints { (make) in
196 | make.bottom.equalToSuperview().offset(-Metric.marginButtonLeftRight)
197 | make.top.equalToSuperview().offset(Metric.marginButtonLeftRight)
198 | make.left.equalToSuperview().offset(Metric.marginButtonLeftRight)
199 | make.width.equalTo(Metric.globalButtonWidth)
200 | }
201 |
202 | spaceButton.snp.makeConstraints { (make) in
203 | make.bottom.equalToSuperview().offset(-Metric.marginButtonLeftRight)
204 | make.top.equalToSuperview().offset(Metric.marginButtonLeftRight)
205 | make.left.equalTo(globalButton.snp.right).offset(Metric.marginButtonLeftRight)
206 | }
207 | } else {
208 | spaceButton.snp.makeConstraints { (make) in
209 | make.bottom.equalToSuperview().offset(-Metric.marginButtonLeftRight)
210 | make.top.equalToSuperview().offset(Metric.marginButtonLeftRight)
211 | make.left.equalToSuperview().offset(Metric.marginButtonLeftRight)
212 | }
213 | }
214 |
215 | deleteButton.snp.makeConstraints { (make) in
216 | make.bottom.equalToSuperview().offset(-Metric.marginButtonLeftRight)
217 | make.top.equalToSuperview().offset(Metric.marginButtonLeftRight)
218 | make.left.equalTo(spaceButton.snp.right).offset(Metric.marginButtonLeftRight)
219 | make.width.equalTo(Metric.deleteButtonWidth)
220 | }
221 |
222 | enterButton.snp.makeConstraints { (make) in
223 | make.bottom.equalToSuperview().offset(-Metric.marginButtonLeftRight)
224 | make.top.equalToSuperview().offset(Metric.marginButtonLeftRight)
225 | make.left.equalTo(deleteButton.snp.right).offset(Metric.marginButtonLeftRight)
226 | make.right.equalToSuperview().offset(-Metric.marginButtonLeftRight)
227 | make.width.equalTo(Metric.enterButtonWidth)
228 | }
229 | }
230 |
231 | func bind(reactor: KeyboardViewReactor) {
232 |
233 | // Action
234 | rx.viewDidLoad
235 | .map { _ in Reactor.Action.loadWords }
236 | .bind(to: reactor.action)
237 | .disposed(by: self.disposeBag)
238 |
239 | self.spaceButton.rx.tap
240 | .subscribe(onNext: { [weak self] _ in
241 | guard let self = self else { return }
242 | self.tapSpaceBar()
243 | }).disposed(by: self.disposeBag)
244 |
245 | self.globalButton.rx.tap
246 | .subscribe(onNext: { [weak self] _ in
247 | guard let self = self else { return }
248 | self.tapGlobal()
249 | }).disposed(by: self.disposeBag)
250 |
251 | self.deleteButton.rx.tap
252 | .subscribe(onNext: { [weak self] _ in
253 | guard let self = self else { return }
254 | self.tapDelete()
255 | }).disposed(by: self.disposeBag)
256 |
257 | self.enterButton.rx.tap
258 | .subscribe(onNext: { [weak self] _ in
259 | guard let self = self else { return }
260 | self.tapEnter()
261 | }).disposed(by: self.disposeBag)
262 |
263 | // State
264 |
265 | reactor.state.map { $0.sections }
266 | .bind(to: tableView.rx.items(dataSource: self.dataSource!))
267 | .disposed(by: self.disposeBag)
268 |
269 | reactor.state.map { $0.sections.first?.items }
270 | .subscribe(onNext: { [weak self] items in
271 | guard let self = self else { return }
272 | if let items = items {
273 | if items.isEmpty {
274 | self.emptyView.isHidden = false
275 | } else {
276 | self.emptyView.isHidden = true
277 | }
278 | }
279 | })
280 | .disposed(by: self.disposeBag)
281 |
282 | tableView.rx.itemSelected
283 | .subscribe(onNext: { [weak tableView] indexPath in
284 | logger.verbose("click")
285 | tableView?.deselectRow(at: indexPath, animated: true)
286 | }).disposed(by: self.disposeBag)
287 |
288 | tableView.rx.itemSelected(dataSource: self.dataSource!)
289 | .subscribe(onNext: { [weak self] sectionItem in
290 | guard let self = self else { return }
291 | switch sectionItem {
292 | case let .listItem(cellReactor):
293 | let message = cellReactor.currentState.list.message
294 | self.textDocumentProxy.insertText(message)
295 | }
296 | })
297 | .disposed(by: self.disposeBag)
298 | }
299 |
300 | // MARK: DataSrouceFactory - configuration
301 |
302 | private func dataSourceFactory() -> RxTableViewSectionedReloadDataSource {
303 | return .init(configureCell: { (dataSource, tableView, indexPath, sectionItem) -> UITableViewCell in
304 | switch sectionItem {
305 | case .listItem(let cellReactor):
306 | let cell = tableView.dequeue(Reusable.listCell, for: indexPath)
307 | cell.reactor = cellReactor
308 | return cell
309 | }
310 | })
311 | }
312 |
313 | override func viewWillLayoutSubviews() {}
314 |
315 | override func textWillChange(_ textInput: UITextInput?) {
316 | // The app is about to change the document's contents. Perform any preparation here.
317 | }
318 |
319 | override func textDidChange(_ textInput: UITextInput?) {
320 | // The app has just changed the document's contents, the document context has been updated.
321 | }
322 |
323 | // MARK: private function
324 |
325 | func tapGlobal() {
326 | logger.verbose("tapGlobal")
327 | self.advanceToNextInputMode()
328 | }
329 |
330 | func tapSpaceBar() {
331 | logger.verbose("tapSpaceBar")
332 | self.textDocumentProxy.insertText(" ")
333 | }
334 |
335 | func tapEnter() {
336 | self.textDocumentProxy.insertText("\n")
337 | }
338 |
339 | func tapDelete() {
340 | self.textDocumentProxy.deleteBackward()
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/keyboard/KeyboardViewReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyboardViewReactor.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import ReactorKit
10 | import RxCocoa
11 | import RxSwift
12 | import UIKit
13 |
14 | final class KeyboardViewReactor: Reactor {
15 |
16 | enum Item {
17 | case word(String)
18 |
19 | var message: String {
20 | switch self {
21 | case let .word(message):
22 | return message
23 | }
24 | }
25 | }
26 |
27 | enum Action {
28 | case loadWords
29 | case getClipboard
30 | }
31 |
32 | enum Mutation {
33 | case loadWords
34 | case getClipboard
35 | }
36 |
37 | struct State {
38 |
39 | var words: [String] = []
40 | var toastMessage: String?
41 | var clipboardString: String?
42 |
43 | var sections: [ListSection] {
44 | let sectionItems = words.map { word -> ListCellReactor in
45 | return ListCellReactor(list: Item.word(word))
46 | }.map(ListSectionItem.listItem)
47 | return [.list(sectionItems)]
48 | }
49 | }
50 |
51 | let initialState: State
52 |
53 | // MARK: Initializing
54 |
55 | init() {
56 | initialState = State()
57 | }
58 |
59 | // MARK: Mutate
60 |
61 | func mutate(action: Action) -> Observable {
62 | switch action {
63 | case .loadWords:
64 | return .just(Mutation.loadWords)
65 | case .getClipboard:
66 | return .just(Mutation.getClipboard)
67 | }
68 | }
69 |
70 | // MARK: Reduce
71 |
72 | func reduce(state: State, mutation: Mutation) -> State {
73 | var state = state
74 | switch mutation {
75 | case .loadWords:
76 | let words = self.getWords()
77 | state.words = words
78 | return state
79 | case .getClipboard:
80 | let words = self.getPasteboard()
81 | state.clipboardString = words
82 | return state
83 | }
84 | }
85 |
86 | // MARK: Private
87 | private func getWords() -> [String] {
88 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return [] }
89 | if let data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
90 | logger.verbose(data)
91 | return data
92 | }
93 |
94 | return []
95 | }
96 |
97 | private func setPasteboard(string: String) {
98 | UIPasteboard.general.string = string
99 | }
100 |
101 | private func getPasteboard() -> String? {
102 | if let string = UIPasteboard.general.string {
103 | return string
104 | }
105 |
106 | return nil
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/keyboard/Sections/ListSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListSection.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | enum ListSection {
13 | case list([ListSectionItem])
14 | }
15 |
16 | extension ListSection: SectionModelType {
17 |
18 | typealias Identify = String
19 | typealias Item = ListSectionItem
20 | var identify: String {
21 | return ""
22 | }
23 |
24 | var items: [ListSectionItem] {
25 | switch self {
26 | case .list(let items):
27 | return items
28 | }
29 | }
30 |
31 | init(original: ListSection, items: [Item]) {
32 | switch original {
33 | case .list:
34 | self = .list(items)
35 | }
36 | }
37 | }
38 |
39 | enum ListSectionItem {
40 | case listItem(ListCellReactor)
41 | }
42 |
--------------------------------------------------------------------------------
/keyboard/Views/ListCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListCell.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import ReactorKit
12 | import RxCocoa
13 | import RxSwift
14 |
15 | final class ListCell: BaseTableViewCell, ReactorKit.View {
16 |
17 | // MARK: Properties
18 | typealias Reactor = ListCellReactor
19 |
20 | // MARK: Initializing
21 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
22 | super.init(style: style, reuseIdentifier: reuseIdentifier)
23 | self.accessoryType = .none
24 | self.textLabel?.font = UIFont.systemFont(ofSize: 14.0)
25 | self.textLabel?.textColor = Color.title
26 | }
27 |
28 | required init?(coder aDecoder: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 |
32 | // MARK: Initializing
33 |
34 | override func addViews() {
35 | super.addViews()
36 | self.contentView.backgroundColor = Color.keyboardListBackground
37 | self.selectionStyle = .none
38 | }
39 |
40 | override func setupConstraints() {
41 | super.setupConstraints()
42 | }
43 |
44 | // MARK: Binding
45 |
46 | func bind(reactor: ListCellReactor) {
47 |
48 | reactor.state.map { $0.list.message }
49 | .distinctUntilChanged()
50 | .bind(to: self.textLabel!.rx.text)
51 | .disposed(by: self.disposeBag)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/keyboard/Views/ListCellReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListCellReactor.swift
3 | // keyboard
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import ReactorKit
10 | import RxCocoa
11 | import RxSwift
12 |
13 | final class ListCellReactor: Reactor {
14 | typealias Action = NoAction
15 | typealias Mutaiton = NoMutation
16 |
17 | struct State {
18 | var list: KeyboardViewReactor.Item
19 | }
20 |
21 | let initialState: State
22 |
23 | init(list: KeyboardViewReactor.Item) {
24 | initialState = State(list: list)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/keyboard/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /*
2 | infoPlist.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 |
9 | "CFBundleDisplayName" = "Keyboard-Example";
10 | "CFBundleDevelopmentRegion" = "en_US";
11 |
--------------------------------------------------------------------------------
/keyboard/keyboard.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.com.tmsae.keyboardExample
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/keyboard/ko.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /*
2 | infoPlist.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 |
9 | "CFBundleDisplayName" = "Keyboard-Example";
10 | "CFBundleDevelopmentRegion" = "ko_KR";
11 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2325D6B6E78502333B03A1F1 /* Pods_keyboard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 968073ACABAB3358884C79DC /* Pods_keyboard.framework */; };
11 | CCBECB9BD5869123E121BC84 /* Pods_reactorkitKeyboardExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F01FA2BC9C3FA2798570C834 /* Pods_reactorkitKeyboardExample.framework */; };
12 | ED0EFE11244EC62D00608FDD /* Pods-reactorkitKeyboardExample-acknowledgements.plist in Resources */ = {isa = PBXBuildFile; fileRef = ED0EFE10244EC62D00608FDD /* Pods-reactorkitKeyboardExample-acknowledgements.plist */; };
13 | ED0EFE14244ECBEF00608FDD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = ED0EFE16244ECBEF00608FDD /* InfoPlist.strings */; };
14 | ED15C026244EDA9000483E20 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EDED22CE244E0CD3004503BB /* Localizable.strings */; };
15 | ED15C029244EDABD00483E20 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = ED15C02B244EDABD00483E20 /* InfoPlist.strings */; };
16 | ED15C02E244EDB7A00483E20 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED15C02D244EDB7A00483E20 /* UIColor.swift */; };
17 | ED15C02F244EDBA700483E20 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED15C02D244EDB7A00483E20 /* UIColor.swift */; };
18 | ED8A0173244E03B100D0C796 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8A0172244E03B100D0C796 /* AppDelegate.swift */; };
19 | ED8A0177244E03B100D0C796 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8A0176244E03B100D0C796 /* ViewController.swift */; };
20 | ED8A017A244E03B100D0C796 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED8A0178244E03B100D0C796 /* Main.storyboard */; };
21 | ED8A017C244E03B300D0C796 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ED8A017B244E03B300D0C796 /* Assets.xcassets */; };
22 | ED8A017F244E03B300D0C796 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED8A017D244E03B300D0C796 /* LaunchScreen.storyboard */; };
23 | EDED2298244E079A004503BB /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED2297244E079A004503BB /* BaseViewController.swift */; };
24 | EDED229A244E07C7004503BB /* BaseNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED2299244E07C7004503BB /* BaseNavigationController.swift */; };
25 | EDED229C244E07E5004503BB /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED229B244E07E5004503BB /* BaseTableViewCell.swift */; };
26 | EDED229E244E0807004503BB /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED229D244E0807004503BB /* Logger.swift */; };
27 | EDED22A0244E08A4004503BB /* MainViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED229F244E08A4004503BB /* MainViewReactor.swift */; };
28 | EDED22A2244E08C0004503BB /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22A1244E08C0004503BB /* MainViewController.swift */; };
29 | EDED22A5244E08F2004503BB /* MainTableViewCellReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22A4244E08F2004503BB /* MainTableViewCellReactor.swift */; };
30 | EDED22A7244E0900004503BB /* MainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22A6244E0900004503BB /* MainTableViewCell.swift */; };
31 | EDED22A9244E0926004503BB /* MainSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22A8244E0926004503BB /* MainSection.swift */; };
32 | EDED22AC244E0956004503BB /* Utillity.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22AB244E0956004503BB /* Utillity.swift */; };
33 | EDED22AE244E096E004503BB /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22AD244E096E004503BB /* Constants.swift */; };
34 | EDED22B1244E09BD004503BB /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22B0244E09BD004503BB /* UITableView+Rx.swift */; };
35 | EDED22B9244E09E6004503BB /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22B8244E09E6004503BB /* KeyboardViewController.swift */; };
36 | EDED22BD244E09E6004503BB /* keyboard.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = EDED22B6244E09E6004503BB /* keyboard.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
37 | EDED22C3244E0A19004503BB /* GlobalColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22C2244E0A19004503BB /* GlobalColors.swift */; };
38 | EDED22C5244E0B28004503BB /* WriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22C4244E0B28004503BB /* WriteViewController.swift */; };
39 | EDED22C7244E0B38004503BB /* WriteViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22C6244E0B38004503BB /* WriteViewReactor.swift */; };
40 | EDED22CC244E0CD3004503BB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EDED22CE244E0CD3004503BB /* Localizable.strings */; };
41 | EDED22D1244E0E2A004503BB /* SettingsViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22D0244E0E2A004503BB /* SettingsViewReactor.swift */; };
42 | EDED22D3244E0E3A004503BB /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22D2244E0E3A004503BB /* SettingsViewController.swift */; };
43 | EDED22D5244E0EF1004503BB /* SettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22D4244E0EF1004503BB /* SettingCell.swift */; };
44 | EDED22D7244E0F0C004503BB /* SettingCellReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22D6244E0F0C004503BB /* SettingCellReactor.swift */; };
45 | EDED22D9244E0F30004503BB /* SettingMenuTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22D8244E0F30004503BB /* SettingMenuTypes.swift */; };
46 | EDED22DB244E0F4E004503BB /* SettingSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22DA244E0F4E004503BB /* SettingSection.swift */; };
47 | EDED22DD244E0FC1004503BB /* SettingFooterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22DC244E0FC1004503BB /* SettingFooterType.swift */; };
48 | EDED22DF244E1025004503BB /* SettingSectionFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22DE244E1025004503BB /* SettingSectionFooterView.swift */; };
49 | EDED22E1244E1030004503BB /* SettingSectionFooterViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22E0244E1030004503BB /* SettingSectionFooterViewReactor.swift */; };
50 | EDED22E5244E1168004503BB /* ListCellReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22E4244E1168004503BB /* ListCellReactor.swift */; };
51 | EDED22E7244E1171004503BB /* ListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22E6244E1171004503BB /* ListCell.swift */; };
52 | EDED22E9244E1191004503BB /* ListSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22E8244E1191004503BB /* ListSection.swift */; };
53 | EDED22EB244E11A9004503BB /* BaseInputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22EA244E11A9004503BB /* BaseInputViewController.swift */; };
54 | EDED22ED244E11CA004503BB /* KeyboardViewReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22EC244E11CA004503BB /* KeyboardViewReactor.swift */; };
55 | EDED22F0244E1218004503BB /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED229B244E07E5004503BB /* BaseTableViewCell.swift */; };
56 | EDED22F1244E1220004503BB /* GlobalColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22C2244E0A19004503BB /* GlobalColors.swift */; };
57 | EDED22F2244E1223004503BB /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22AD244E096E004503BB /* Constants.swift */; };
58 | EDED22F5244E126B004503BB /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22F4244E126B004503BB /* UIButton.swift */; };
59 | EDED22F6244E127E004503BB /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED229D244E0807004503BB /* Logger.swift */; };
60 | EDED22F7244E12C1004503BB /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDED22B0244E09BD004503BB /* UITableView+Rx.swift */; };
61 | EDED22FA244E1504004503BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ED8A017B244E03B300D0C796 /* Assets.xcassets */; };
62 | /* End PBXBuildFile section */
63 |
64 | /* Begin PBXContainerItemProxy section */
65 | EDED22BB244E09E6004503BB /* PBXContainerItemProxy */ = {
66 | isa = PBXContainerItemProxy;
67 | containerPortal = ED8A0167244E03B100D0C796 /* Project object */;
68 | proxyType = 1;
69 | remoteGlobalIDString = EDED22B5244E09E6004503BB;
70 | remoteInfo = keyboard;
71 | };
72 | /* End PBXContainerItemProxy section */
73 |
74 | /* Begin PBXCopyFilesBuildPhase section */
75 | EDED22C1244E09E6004503BB /* Embed App Extensions */ = {
76 | isa = PBXCopyFilesBuildPhase;
77 | buildActionMask = 2147483647;
78 | dstPath = "";
79 | dstSubfolderSpec = 13;
80 | files = (
81 | EDED22BD244E09E6004503BB /* keyboard.appex in Embed App Extensions */,
82 | );
83 | name = "Embed App Extensions";
84 | runOnlyForDeploymentPostprocessing = 0;
85 | };
86 | /* End PBXCopyFilesBuildPhase section */
87 |
88 | /* Begin PBXFileReference section */
89 | 2038FF17147E219B043ABEAB /* Pods-reactorkitKeyboardExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-reactorkitKeyboardExample.release.xcconfig"; path = "Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample.release.xcconfig"; sourceTree = ""; };
90 | 6AFD01CE0785D20809E99E2B /* Pods-keyboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyboard.release.xcconfig"; path = "Target Support Files/Pods-keyboard/Pods-keyboard.release.xcconfig"; sourceTree = ""; };
91 | 6BC67B005AA82AFD5DBBB4B5 /* Pods-keyboard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyboard.debug.xcconfig"; path = "Target Support Files/Pods-keyboard/Pods-keyboard.debug.xcconfig"; sourceTree = ""; };
92 | 968073ACABAB3358884C79DC /* Pods_keyboard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_keyboard.framework; sourceTree = BUILT_PRODUCTS_DIR; };
93 | AA0AB43F661D32464E4E23C4 /* Pods-reactorkitKeyboardExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-reactorkitKeyboardExample.debug.xcconfig"; path = "Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample.debug.xcconfig"; sourceTree = ""; };
94 | ED0EFE10244EC62D00608FDD /* Pods-reactorkitKeyboardExample-acknowledgements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = "Pods-reactorkitKeyboardExample-acknowledgements.plist"; path = "Pods/Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample-acknowledgements.plist"; sourceTree = SOURCE_ROOT; };
95 | ED0EFE15244ECBEF00608FDD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
96 | ED0EFE17244ECBF000608FDD /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = ""; };
97 | ED15C02A244EDABD00483E20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
98 | ED15C02C244EDABE00483E20 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = ""; };
99 | ED15C02D244EDB7A00483E20 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; };
100 | ED8A016F244E03B100D0C796 /* reactorkitKeyboardExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = reactorkitKeyboardExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
101 | ED8A0172244E03B100D0C796 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
102 | ED8A0176244E03B100D0C796 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
103 | ED8A0179244E03B100D0C796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
104 | ED8A017B244E03B300D0C796 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
105 | ED8A017E244E03B300D0C796 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
106 | ED8A0180244E03B300D0C796 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
107 | EDED2297244E079A004503BB /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; };
108 | EDED2299244E07C7004503BB /* BaseNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNavigationController.swift; sourceTree = ""; };
109 | EDED229B244E07E5004503BB /* BaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewCell.swift; sourceTree = ""; };
110 | EDED229D244E0807004503BB /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; };
111 | EDED229F244E08A4004503BB /* MainViewReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewReactor.swift; sourceTree = ""; };
112 | EDED22A1244E08C0004503BB /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; };
113 | EDED22A4244E08F2004503BB /* MainTableViewCellReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTableViewCellReactor.swift; sourceTree = ""; };
114 | EDED22A6244E0900004503BB /* MainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTableViewCell.swift; sourceTree = ""; };
115 | EDED22A8244E0926004503BB /* MainSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSection.swift; sourceTree = ""; };
116 | EDED22AB244E0956004503BB /* Utillity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utillity.swift; sourceTree = ""; };
117 | EDED22AD244E096E004503BB /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; };
118 | EDED22B0244E09BD004503BB /* UITableView+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+Rx.swift"; sourceTree = ""; };
119 | EDED22B6244E09E6004503BB /* keyboard.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = keyboard.appex; sourceTree = BUILT_PRODUCTS_DIR; };
120 | EDED22B8244E09E6004503BB /* KeyboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardViewController.swift; sourceTree = ""; };
121 | EDED22BA244E09E6004503BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
122 | EDED22C2244E0A19004503BB /* GlobalColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalColors.swift; sourceTree = ""; };
123 | EDED22C4244E0B28004503BB /* WriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteViewController.swift; sourceTree = ""; };
124 | EDED22C6244E0B38004503BB /* WriteViewReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteViewReactor.swift; sourceTree = ""; };
125 | EDED22C8244E0C6A004503BB /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Main.strings; sourceTree = ""; };
126 | EDED22C9244E0C6A004503BB /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/LaunchScreen.strings; sourceTree = ""; };
127 | EDED22CD244E0CD3004503BB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; };
128 | EDED22CF244E0CD4004503BB /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; };
129 | EDED22D0244E0E2A004503BB /* SettingsViewReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewReactor.swift; sourceTree = ""; };
130 | EDED22D2244E0E3A004503BB /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
131 | EDED22D4244E0EF1004503BB /* SettingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingCell.swift; sourceTree = ""; };
132 | EDED22D6244E0F0C004503BB /* SettingCellReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingCellReactor.swift; sourceTree = ""; };
133 | EDED22D8244E0F30004503BB /* SettingMenuTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingMenuTypes.swift; sourceTree = ""; };
134 | EDED22DA244E0F4E004503BB /* SettingSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSection.swift; sourceTree = ""; };
135 | EDED22DC244E0FC1004503BB /* SettingFooterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingFooterType.swift; sourceTree = ""; };
136 | EDED22DE244E1025004503BB /* SettingSectionFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSectionFooterView.swift; sourceTree = ""; };
137 | EDED22E0244E1030004503BB /* SettingSectionFooterViewReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingSectionFooterViewReactor.swift; sourceTree = ""; };
138 | EDED22E4244E1168004503BB /* ListCellReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCellReactor.swift; sourceTree = ""; };
139 | EDED22E6244E1171004503BB /* ListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCell.swift; sourceTree = ""; };
140 | EDED22E8244E1191004503BB /* ListSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListSection.swift; sourceTree = ""; };
141 | EDED22EA244E11A9004503BB /* BaseInputViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseInputViewController.swift; sourceTree = ""; };
142 | EDED22EC244E11CA004503BB /* KeyboardViewReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardViewReactor.swift; sourceTree = ""; };
143 | EDED22F4244E126B004503BB /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = ""; };
144 | EDED22F8244E138C004503BB /* reactorkitKeyboardExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = reactorkitKeyboardExample.entitlements; sourceTree = ""; };
145 | EDED22F9244E1463004503BB /* keyboard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = keyboard.entitlements; sourceTree = ""; };
146 | F01FA2BC9C3FA2798570C834 /* Pods_reactorkitKeyboardExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_reactorkitKeyboardExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
147 | /* End PBXFileReference section */
148 |
149 | /* Begin PBXFrameworksBuildPhase section */
150 | ED8A016C244E03B100D0C796 /* Frameworks */ = {
151 | isa = PBXFrameworksBuildPhase;
152 | buildActionMask = 2147483647;
153 | files = (
154 | CCBECB9BD5869123E121BC84 /* Pods_reactorkitKeyboardExample.framework in Frameworks */,
155 | );
156 | runOnlyForDeploymentPostprocessing = 0;
157 | };
158 | EDED22B3244E09E6004503BB /* Frameworks */ = {
159 | isa = PBXFrameworksBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 2325D6B6E78502333B03A1F1 /* Pods_keyboard.framework in Frameworks */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXFrameworksBuildPhase section */
167 |
168 | /* Begin PBXGroup section */
169 | AC481367D8F21772CD5D51A1 /* Frameworks */ = {
170 | isa = PBXGroup;
171 | children = (
172 | F01FA2BC9C3FA2798570C834 /* Pods_reactorkitKeyboardExample.framework */,
173 | 968073ACABAB3358884C79DC /* Pods_keyboard.framework */,
174 | );
175 | name = Frameworks;
176 | sourceTree = "";
177 | };
178 | CC6DAB0B1CEA65BD340F2FCB /* Pods */ = {
179 | isa = PBXGroup;
180 | children = (
181 | AA0AB43F661D32464E4E23C4 /* Pods-reactorkitKeyboardExample.debug.xcconfig */,
182 | 2038FF17147E219B043ABEAB /* Pods-reactorkitKeyboardExample.release.xcconfig */,
183 | 6BC67B005AA82AFD5DBBB4B5 /* Pods-keyboard.debug.xcconfig */,
184 | 6AFD01CE0785D20809E99E2B /* Pods-keyboard.release.xcconfig */,
185 | );
186 | path = Pods;
187 | sourceTree = "";
188 | };
189 | ED8A0166244E03B100D0C796 = {
190 | isa = PBXGroup;
191 | children = (
192 | ED8A0171244E03B100D0C796 /* reactorkitKeyboardExample */,
193 | EDED22B7244E09E6004503BB /* keyboard */,
194 | ED8A0170244E03B100D0C796 /* Products */,
195 | CC6DAB0B1CEA65BD340F2FCB /* Pods */,
196 | AC481367D8F21772CD5D51A1 /* Frameworks */,
197 | );
198 | sourceTree = "";
199 | };
200 | ED8A0170244E03B100D0C796 /* Products */ = {
201 | isa = PBXGroup;
202 | children = (
203 | ED8A016F244E03B100D0C796 /* reactorkitKeyboardExample.app */,
204 | EDED22B6244E09E6004503BB /* keyboard.appex */,
205 | );
206 | name = Products;
207 | sourceTree = "";
208 | };
209 | ED8A0171244E03B100D0C796 /* reactorkitKeyboardExample */ = {
210 | isa = PBXGroup;
211 | children = (
212 | EDED22F8244E138C004503BB /* reactorkitKeyboardExample.entitlements */,
213 | EDED22AA244E094A004503BB /* Common */,
214 | EDED2296244E0777004503BB /* Logging */,
215 | EDED2290244E069E004503BB /* Base */,
216 | EDED2291244E06A4004503BB /* ViewControllers */,
217 | EDED228F244E0697004503BB /* Views */,
218 | EDED2294244E06B9004503BB /* Extensions */,
219 | EDED2293244E06B5004503BB /* Types */,
220 | EDED2292244E06AF004503BB /* Sections */,
221 | ED8A0172244E03B100D0C796 /* AppDelegate.swift */,
222 | ED8A0176244E03B100D0C796 /* ViewController.swift */,
223 | ED8A0178244E03B100D0C796 /* Main.storyboard */,
224 | EDED2295244E0748004503BB /* Supported Files */,
225 | ED8A017D244E03B300D0C796 /* LaunchScreen.storyboard */,
226 | ED8A0180244E03B300D0C796 /* Info.plist */,
227 | );
228 | path = reactorkitKeyboardExample;
229 | sourceTree = "";
230 | };
231 | EDED228F244E0697004503BB /* Views */ = {
232 | isa = PBXGroup;
233 | children = (
234 | EDED22A3244E08E4004503BB /* Cells */,
235 | );
236 | path = Views;
237 | sourceTree = "";
238 | };
239 | EDED2290244E069E004503BB /* Base */ = {
240 | isa = PBXGroup;
241 | children = (
242 | EDED2297244E079A004503BB /* BaseViewController.swift */,
243 | EDED2299244E07C7004503BB /* BaseNavigationController.swift */,
244 | EDED229B244E07E5004503BB /* BaseTableViewCell.swift */,
245 | );
246 | path = Base;
247 | sourceTree = "";
248 | };
249 | EDED2291244E06A4004503BB /* ViewControllers */ = {
250 | isa = PBXGroup;
251 | children = (
252 | EDED229F244E08A4004503BB /* MainViewReactor.swift */,
253 | EDED22A1244E08C0004503BB /* MainViewController.swift */,
254 | EDED22C4244E0B28004503BB /* WriteViewController.swift */,
255 | EDED22C6244E0B38004503BB /* WriteViewReactor.swift */,
256 | EDED22D0244E0E2A004503BB /* SettingsViewReactor.swift */,
257 | EDED22D2244E0E3A004503BB /* SettingsViewController.swift */,
258 | );
259 | path = ViewControllers;
260 | sourceTree = "";
261 | };
262 | EDED2292244E06AF004503BB /* Sections */ = {
263 | isa = PBXGroup;
264 | children = (
265 | EDED22A8244E0926004503BB /* MainSection.swift */,
266 | EDED22DA244E0F4E004503BB /* SettingSection.swift */,
267 | );
268 | path = Sections;
269 | sourceTree = "";
270 | };
271 | EDED2293244E06B5004503BB /* Types */ = {
272 | isa = PBXGroup;
273 | children = (
274 | EDED22D8244E0F30004503BB /* SettingMenuTypes.swift */,
275 | EDED22DC244E0FC1004503BB /* SettingFooterType.swift */,
276 | );
277 | path = Types;
278 | sourceTree = "";
279 | };
280 | EDED2294244E06B9004503BB /* Extensions */ = {
281 | isa = PBXGroup;
282 | children = (
283 | EDED22AF244E09B0004503BB /* Rx */,
284 | );
285 | path = Extensions;
286 | sourceTree = "";
287 | };
288 | EDED2295244E0748004503BB /* Supported Files */ = {
289 | isa = PBXGroup;
290 | children = (
291 | ED0EFE10244EC62D00608FDD /* Pods-reactorkitKeyboardExample-acknowledgements.plist */,
292 | ED8A017B244E03B300D0C796 /* Assets.xcassets */,
293 | EDED22CE244E0CD3004503BB /* Localizable.strings */,
294 | ED15C02B244EDABD00483E20 /* InfoPlist.strings */,
295 | );
296 | path = "Supported Files";
297 | sourceTree = "";
298 | };
299 | EDED2296244E0777004503BB /* Logging */ = {
300 | isa = PBXGroup;
301 | children = (
302 | EDED229D244E0807004503BB /* Logger.swift */,
303 | );
304 | path = Logging;
305 | sourceTree = "";
306 | };
307 | EDED22A3244E08E4004503BB /* Cells */ = {
308 | isa = PBXGroup;
309 | children = (
310 | EDED22A4244E08F2004503BB /* MainTableViewCellReactor.swift */,
311 | EDED22A6244E0900004503BB /* MainTableViewCell.swift */,
312 | EDED22D4244E0EF1004503BB /* SettingCell.swift */,
313 | EDED22D6244E0F0C004503BB /* SettingCellReactor.swift */,
314 | EDED22DE244E1025004503BB /* SettingSectionFooterView.swift */,
315 | EDED22E0244E1030004503BB /* SettingSectionFooterViewReactor.swift */,
316 | );
317 | path = Cells;
318 | sourceTree = "";
319 | };
320 | EDED22AA244E094A004503BB /* Common */ = {
321 | isa = PBXGroup;
322 | children = (
323 | EDED22AB244E0956004503BB /* Utillity.swift */,
324 | EDED22AD244E096E004503BB /* Constants.swift */,
325 | EDED22C2244E0A19004503BB /* GlobalColors.swift */,
326 | ED15C02D244EDB7A00483E20 /* UIColor.swift */,
327 | );
328 | path = Common;
329 | sourceTree = "";
330 | };
331 | EDED22AF244E09B0004503BB /* Rx */ = {
332 | isa = PBXGroup;
333 | children = (
334 | EDED22B0244E09BD004503BB /* UITableView+Rx.swift */,
335 | );
336 | path = Rx;
337 | sourceTree = "";
338 | };
339 | EDED22B7244E09E6004503BB /* keyboard */ = {
340 | isa = PBXGroup;
341 | children = (
342 | EDED22F9244E1463004503BB /* keyboard.entitlements */,
343 | EDED22F3244E1256004503BB /* Extensions */,
344 | EDED22E3244E1115004503BB /* Views */,
345 | EDED22E2244E10F8004503BB /* Sections */,
346 | EDED22EC244E11CA004503BB /* KeyboardViewReactor.swift */,
347 | EDED22B8244E09E6004503BB /* KeyboardViewController.swift */,
348 | EDED22BA244E09E6004503BB /* Info.plist */,
349 | EDED22EA244E11A9004503BB /* BaseInputViewController.swift */,
350 | ED0EFE16244ECBEF00608FDD /* InfoPlist.strings */,
351 | );
352 | path = keyboard;
353 | sourceTree = "";
354 | };
355 | EDED22E2244E10F8004503BB /* Sections */ = {
356 | isa = PBXGroup;
357 | children = (
358 | EDED22E8244E1191004503BB /* ListSection.swift */,
359 | );
360 | path = Sections;
361 | sourceTree = "";
362 | };
363 | EDED22E3244E1115004503BB /* Views */ = {
364 | isa = PBXGroup;
365 | children = (
366 | EDED22E4244E1168004503BB /* ListCellReactor.swift */,
367 | EDED22E6244E1171004503BB /* ListCell.swift */,
368 | );
369 | path = Views;
370 | sourceTree = "";
371 | };
372 | EDED22F3244E1256004503BB /* Extensions */ = {
373 | isa = PBXGroup;
374 | children = (
375 | EDED22F4244E126B004503BB /* UIButton.swift */,
376 | );
377 | path = Extensions;
378 | sourceTree = "";
379 | };
380 | /* End PBXGroup section */
381 |
382 | /* Begin PBXNativeTarget section */
383 | ED8A016E244E03B100D0C796 /* reactorkitKeyboardExample */ = {
384 | isa = PBXNativeTarget;
385 | buildConfigurationList = ED8A0183244E03B300D0C796 /* Build configuration list for PBXNativeTarget "reactorkitKeyboardExample" */;
386 | buildPhases = (
387 | 5F6A9D0E4A91C652AA66CB16 /* [CP] Check Pods Manifest.lock */,
388 | ED8A016B244E03B100D0C796 /* Sources */,
389 | ED8A016C244E03B100D0C796 /* Frameworks */,
390 | ED8A016D244E03B100D0C796 /* Resources */,
391 | B21E8754D643CAA2D1957BB5 /* [CP] Embed Pods Frameworks */,
392 | EDED22C1244E09E6004503BB /* Embed App Extensions */,
393 | );
394 | buildRules = (
395 | );
396 | dependencies = (
397 | EDED22BC244E09E6004503BB /* PBXTargetDependency */,
398 | );
399 | name = reactorkitKeyboardExample;
400 | productName = reactorkitKeyboardExample;
401 | productReference = ED8A016F244E03B100D0C796 /* reactorkitKeyboardExample.app */;
402 | productType = "com.apple.product-type.application";
403 | };
404 | EDED22B5244E09E6004503BB /* keyboard */ = {
405 | isa = PBXNativeTarget;
406 | buildConfigurationList = EDED22BE244E09E6004503BB /* Build configuration list for PBXNativeTarget "keyboard" */;
407 | buildPhases = (
408 | 479BFEF2E5A7E0CAFBAB9FFA /* [CP] Check Pods Manifest.lock */,
409 | EDED22B2244E09E6004503BB /* Sources */,
410 | EDED22B3244E09E6004503BB /* Frameworks */,
411 | EDED22B4244E09E6004503BB /* Resources */,
412 | );
413 | buildRules = (
414 | );
415 | dependencies = (
416 | );
417 | name = keyboard;
418 | productName = keyboard;
419 | productReference = EDED22B6244E09E6004503BB /* keyboard.appex */;
420 | productType = "com.apple.product-type.app-extension";
421 | };
422 | /* End PBXNativeTarget section */
423 |
424 | /* Begin PBXProject section */
425 | ED8A0167244E03B100D0C796 /* Project object */ = {
426 | isa = PBXProject;
427 | attributes = {
428 | LastSwiftUpdateCheck = 1140;
429 | LastUpgradeCheck = 1130;
430 | ORGANIZATIONNAME = tmsae;
431 | TargetAttributes = {
432 | ED8A016E244E03B100D0C796 = {
433 | CreatedOnToolsVersion = 11.3.1;
434 | };
435 | EDED22B5244E09E6004503BB = {
436 | CreatedOnToolsVersion = 11.4;
437 | };
438 | };
439 | };
440 | buildConfigurationList = ED8A016A244E03B100D0C796 /* Build configuration list for PBXProject "reactorkitKeyboardExample" */;
441 | compatibilityVersion = "Xcode 9.3";
442 | developmentRegion = en;
443 | hasScannedForEncodings = 0;
444 | knownRegions = (
445 | en,
446 | Base,
447 | ko,
448 | );
449 | mainGroup = ED8A0166244E03B100D0C796;
450 | productRefGroup = ED8A0170244E03B100D0C796 /* Products */;
451 | projectDirPath = "";
452 | projectRoot = "";
453 | targets = (
454 | ED8A016E244E03B100D0C796 /* reactorkitKeyboardExample */,
455 | EDED22B5244E09E6004503BB /* keyboard */,
456 | );
457 | };
458 | /* End PBXProject section */
459 |
460 | /* Begin PBXResourcesBuildPhase section */
461 | ED8A016D244E03B100D0C796 /* Resources */ = {
462 | isa = PBXResourcesBuildPhase;
463 | buildActionMask = 2147483647;
464 | files = (
465 | ED8A017F244E03B300D0C796 /* LaunchScreen.storyboard in Resources */,
466 | ED15C029244EDABD00483E20 /* InfoPlist.strings in Resources */,
467 | ED0EFE11244EC62D00608FDD /* Pods-reactorkitKeyboardExample-acknowledgements.plist in Resources */,
468 | EDED22CC244E0CD3004503BB /* Localizable.strings in Resources */,
469 | ED8A017C244E03B300D0C796 /* Assets.xcassets in Resources */,
470 | ED8A017A244E03B100D0C796 /* Main.storyboard in Resources */,
471 | );
472 | runOnlyForDeploymentPostprocessing = 0;
473 | };
474 | EDED22B4244E09E6004503BB /* Resources */ = {
475 | isa = PBXResourcesBuildPhase;
476 | buildActionMask = 2147483647;
477 | files = (
478 | EDED22FA244E1504004503BB /* Assets.xcassets in Resources */,
479 | ED15C026244EDA9000483E20 /* Localizable.strings in Resources */,
480 | ED0EFE14244ECBEF00608FDD /* InfoPlist.strings in Resources */,
481 | );
482 | runOnlyForDeploymentPostprocessing = 0;
483 | };
484 | /* End PBXResourcesBuildPhase section */
485 |
486 | /* Begin PBXShellScriptBuildPhase section */
487 | 479BFEF2E5A7E0CAFBAB9FFA /* [CP] Check Pods Manifest.lock */ = {
488 | isa = PBXShellScriptBuildPhase;
489 | buildActionMask = 2147483647;
490 | files = (
491 | );
492 | inputFileListPaths = (
493 | );
494 | inputPaths = (
495 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
496 | "${PODS_ROOT}/Manifest.lock",
497 | );
498 | name = "[CP] Check Pods Manifest.lock";
499 | outputFileListPaths = (
500 | );
501 | outputPaths = (
502 | "$(DERIVED_FILE_DIR)/Pods-keyboard-checkManifestLockResult.txt",
503 | );
504 | runOnlyForDeploymentPostprocessing = 0;
505 | shellPath = /bin/sh;
506 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
507 | showEnvVarsInLog = 0;
508 | };
509 | 5F6A9D0E4A91C652AA66CB16 /* [CP] Check Pods Manifest.lock */ = {
510 | isa = PBXShellScriptBuildPhase;
511 | buildActionMask = 2147483647;
512 | files = (
513 | );
514 | inputFileListPaths = (
515 | );
516 | inputPaths = (
517 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
518 | "${PODS_ROOT}/Manifest.lock",
519 | );
520 | name = "[CP] Check Pods Manifest.lock";
521 | outputFileListPaths = (
522 | );
523 | outputPaths = (
524 | "$(DERIVED_FILE_DIR)/Pods-reactorkitKeyboardExample-checkManifestLockResult.txt",
525 | );
526 | runOnlyForDeploymentPostprocessing = 0;
527 | shellPath = /bin/sh;
528 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
529 | showEnvVarsInLog = 0;
530 | };
531 | B21E8754D643CAA2D1957BB5 /* [CP] Embed Pods Frameworks */ = {
532 | isa = PBXShellScriptBuildPhase;
533 | buildActionMask = 2147483647;
534 | files = (
535 | );
536 | inputFileListPaths = (
537 | "${PODS_ROOT}/Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
538 | );
539 | name = "[CP] Embed Pods Frameworks";
540 | outputFileListPaths = (
541 | "${PODS_ROOT}/Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
542 | );
543 | runOnlyForDeploymentPostprocessing = 0;
544 | shellPath = /bin/sh;
545 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-reactorkitKeyboardExample/Pods-reactorkitKeyboardExample-frameworks.sh\"\n";
546 | showEnvVarsInLog = 0;
547 | };
548 | /* End PBXShellScriptBuildPhase section */
549 |
550 | /* Begin PBXSourcesBuildPhase section */
551 | ED8A016B244E03B100D0C796 /* Sources */ = {
552 | isa = PBXSourcesBuildPhase;
553 | buildActionMask = 2147483647;
554 | files = (
555 | EDED22C7244E0B38004503BB /* WriteViewReactor.swift in Sources */,
556 | EDED229A244E07C7004503BB /* BaseNavigationController.swift in Sources */,
557 | EDED22B1244E09BD004503BB /* UITableView+Rx.swift in Sources */,
558 | EDED22A9244E0926004503BB /* MainSection.swift in Sources */,
559 | EDED229E244E0807004503BB /* Logger.swift in Sources */,
560 | EDED22D3244E0E3A004503BB /* SettingsViewController.swift in Sources */,
561 | ED8A0177244E03B100D0C796 /* ViewController.swift in Sources */,
562 | ED8A0173244E03B100D0C796 /* AppDelegate.swift in Sources */,
563 | EDED22AC244E0956004503BB /* Utillity.swift in Sources */,
564 | EDED22DD244E0FC1004503BB /* SettingFooterType.swift in Sources */,
565 | EDED22DB244E0F4E004503BB /* SettingSection.swift in Sources */,
566 | EDED22C3244E0A19004503BB /* GlobalColors.swift in Sources */,
567 | EDED22A7244E0900004503BB /* MainTableViewCell.swift in Sources */,
568 | EDED22E1244E1030004503BB /* SettingSectionFooterViewReactor.swift in Sources */,
569 | EDED22AE244E096E004503BB /* Constants.swift in Sources */,
570 | EDED22DF244E1025004503BB /* SettingSectionFooterView.swift in Sources */,
571 | EDED22A0244E08A4004503BB /* MainViewReactor.swift in Sources */,
572 | EDED22D9244E0F30004503BB /* SettingMenuTypes.swift in Sources */,
573 | EDED22D1244E0E2A004503BB /* SettingsViewReactor.swift in Sources */,
574 | EDED229C244E07E5004503BB /* BaseTableViewCell.swift in Sources */,
575 | EDED22A5244E08F2004503BB /* MainTableViewCellReactor.swift in Sources */,
576 | EDED2298244E079A004503BB /* BaseViewController.swift in Sources */,
577 | ED15C02E244EDB7A00483E20 /* UIColor.swift in Sources */,
578 | EDED22C5244E0B28004503BB /* WriteViewController.swift in Sources */,
579 | EDED22D5244E0EF1004503BB /* SettingCell.swift in Sources */,
580 | EDED22D7244E0F0C004503BB /* SettingCellReactor.swift in Sources */,
581 | EDED22A2244E08C0004503BB /* MainViewController.swift in Sources */,
582 | );
583 | runOnlyForDeploymentPostprocessing = 0;
584 | };
585 | EDED22B2244E09E6004503BB /* Sources */ = {
586 | isa = PBXSourcesBuildPhase;
587 | buildActionMask = 2147483647;
588 | files = (
589 | EDED22F0244E1218004503BB /* BaseTableViewCell.swift in Sources */,
590 | EDED22EB244E11A9004503BB /* BaseInputViewController.swift in Sources */,
591 | EDED22E7244E1171004503BB /* ListCell.swift in Sources */,
592 | EDED22E9244E1191004503BB /* ListSection.swift in Sources */,
593 | EDED22E5244E1168004503BB /* ListCellReactor.swift in Sources */,
594 | EDED22F2244E1223004503BB /* Constants.swift in Sources */,
595 | EDED22ED244E11CA004503BB /* KeyboardViewReactor.swift in Sources */,
596 | EDED22F6244E127E004503BB /* Logger.swift in Sources */,
597 | EDED22F5244E126B004503BB /* UIButton.swift in Sources */,
598 | ED15C02F244EDBA700483E20 /* UIColor.swift in Sources */,
599 | EDED22F7244E12C1004503BB /* UITableView+Rx.swift in Sources */,
600 | EDED22F1244E1220004503BB /* GlobalColors.swift in Sources */,
601 | EDED22B9244E09E6004503BB /* KeyboardViewController.swift in Sources */,
602 | );
603 | runOnlyForDeploymentPostprocessing = 0;
604 | };
605 | /* End PBXSourcesBuildPhase section */
606 |
607 | /* Begin PBXTargetDependency section */
608 | EDED22BC244E09E6004503BB /* PBXTargetDependency */ = {
609 | isa = PBXTargetDependency;
610 | target = EDED22B5244E09E6004503BB /* keyboard */;
611 | targetProxy = EDED22BB244E09E6004503BB /* PBXContainerItemProxy */;
612 | };
613 | /* End PBXTargetDependency section */
614 |
615 | /* Begin PBXVariantGroup section */
616 | ED0EFE16244ECBEF00608FDD /* InfoPlist.strings */ = {
617 | isa = PBXVariantGroup;
618 | children = (
619 | ED0EFE15244ECBEF00608FDD /* en */,
620 | ED0EFE17244ECBF000608FDD /* ko */,
621 | );
622 | name = InfoPlist.strings;
623 | sourceTree = "";
624 | };
625 | ED15C02B244EDABD00483E20 /* InfoPlist.strings */ = {
626 | isa = PBXVariantGroup;
627 | children = (
628 | ED15C02A244EDABD00483E20 /* en */,
629 | ED15C02C244EDABE00483E20 /* ko */,
630 | );
631 | name = InfoPlist.strings;
632 | sourceTree = "";
633 | };
634 | ED8A0178244E03B100D0C796 /* Main.storyboard */ = {
635 | isa = PBXVariantGroup;
636 | children = (
637 | ED8A0179244E03B100D0C796 /* Base */,
638 | EDED22C8244E0C6A004503BB /* ko */,
639 | );
640 | name = Main.storyboard;
641 | sourceTree = "";
642 | };
643 | ED8A017D244E03B300D0C796 /* LaunchScreen.storyboard */ = {
644 | isa = PBXVariantGroup;
645 | children = (
646 | ED8A017E244E03B300D0C796 /* Base */,
647 | EDED22C9244E0C6A004503BB /* ko */,
648 | );
649 | name = LaunchScreen.storyboard;
650 | sourceTree = "";
651 | };
652 | EDED22CE244E0CD3004503BB /* Localizable.strings */ = {
653 | isa = PBXVariantGroup;
654 | children = (
655 | EDED22CD244E0CD3004503BB /* en */,
656 | EDED22CF244E0CD4004503BB /* ko */,
657 | );
658 | name = Localizable.strings;
659 | sourceTree = "";
660 | };
661 | /* End PBXVariantGroup section */
662 |
663 | /* Begin XCBuildConfiguration section */
664 | ED8A0181244E03B300D0C796 /* Debug */ = {
665 | isa = XCBuildConfiguration;
666 | buildSettings = {
667 | ALWAYS_SEARCH_USER_PATHS = NO;
668 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
669 | CLANG_ANALYZER_NONNULL = YES;
670 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
671 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
672 | CLANG_CXX_LIBRARY = "libc++";
673 | CLANG_ENABLE_MODULES = YES;
674 | CLANG_ENABLE_OBJC_ARC = YES;
675 | CLANG_ENABLE_OBJC_WEAK = YES;
676 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
677 | CLANG_WARN_BOOL_CONVERSION = YES;
678 | CLANG_WARN_COMMA = YES;
679 | CLANG_WARN_CONSTANT_CONVERSION = YES;
680 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
681 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
682 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
683 | CLANG_WARN_EMPTY_BODY = YES;
684 | CLANG_WARN_ENUM_CONVERSION = YES;
685 | CLANG_WARN_INFINITE_RECURSION = YES;
686 | CLANG_WARN_INT_CONVERSION = YES;
687 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
688 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
689 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
690 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
691 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
692 | CLANG_WARN_STRICT_PROTOTYPES = YES;
693 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
694 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
695 | CLANG_WARN_UNREACHABLE_CODE = YES;
696 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
697 | COPY_PHASE_STRIP = NO;
698 | DEBUG_INFORMATION_FORMAT = dwarf;
699 | ENABLE_STRICT_OBJC_MSGSEND = YES;
700 | ENABLE_TESTABILITY = YES;
701 | GCC_C_LANGUAGE_STANDARD = gnu11;
702 | GCC_DYNAMIC_NO_PIC = NO;
703 | GCC_NO_COMMON_BLOCKS = YES;
704 | GCC_OPTIMIZATION_LEVEL = 0;
705 | GCC_PREPROCESSOR_DEFINITIONS = (
706 | "DEBUG=1",
707 | "$(inherited)",
708 | );
709 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
710 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
711 | GCC_WARN_UNDECLARED_SELECTOR = YES;
712 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
713 | GCC_WARN_UNUSED_FUNCTION = YES;
714 | GCC_WARN_UNUSED_VARIABLE = YES;
715 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
716 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
717 | MTL_FAST_MATH = YES;
718 | ONLY_ACTIVE_ARCH = YES;
719 | SDKROOT = iphoneos;
720 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
721 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
722 | };
723 | name = Debug;
724 | };
725 | ED8A0182244E03B300D0C796 /* Release */ = {
726 | isa = XCBuildConfiguration;
727 | buildSettings = {
728 | ALWAYS_SEARCH_USER_PATHS = NO;
729 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
730 | CLANG_ANALYZER_NONNULL = YES;
731 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
732 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
733 | CLANG_CXX_LIBRARY = "libc++";
734 | CLANG_ENABLE_MODULES = YES;
735 | CLANG_ENABLE_OBJC_ARC = YES;
736 | CLANG_ENABLE_OBJC_WEAK = YES;
737 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
738 | CLANG_WARN_BOOL_CONVERSION = YES;
739 | CLANG_WARN_COMMA = YES;
740 | CLANG_WARN_CONSTANT_CONVERSION = YES;
741 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
742 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
743 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
744 | CLANG_WARN_EMPTY_BODY = YES;
745 | CLANG_WARN_ENUM_CONVERSION = YES;
746 | CLANG_WARN_INFINITE_RECURSION = YES;
747 | CLANG_WARN_INT_CONVERSION = YES;
748 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
749 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
750 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
751 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
752 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
753 | CLANG_WARN_STRICT_PROTOTYPES = YES;
754 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
755 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
756 | CLANG_WARN_UNREACHABLE_CODE = YES;
757 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
758 | COPY_PHASE_STRIP = NO;
759 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
760 | ENABLE_NS_ASSERTIONS = NO;
761 | ENABLE_STRICT_OBJC_MSGSEND = YES;
762 | GCC_C_LANGUAGE_STANDARD = gnu11;
763 | GCC_NO_COMMON_BLOCKS = YES;
764 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
765 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
766 | GCC_WARN_UNDECLARED_SELECTOR = YES;
767 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
768 | GCC_WARN_UNUSED_FUNCTION = YES;
769 | GCC_WARN_UNUSED_VARIABLE = YES;
770 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
771 | MTL_ENABLE_DEBUG_INFO = NO;
772 | MTL_FAST_MATH = YES;
773 | SDKROOT = iphoneos;
774 | SWIFT_COMPILATION_MODE = wholemodule;
775 | SWIFT_OPTIMIZATION_LEVEL = "-O";
776 | VALIDATE_PRODUCT = YES;
777 | };
778 | name = Release;
779 | };
780 | ED8A0184244E03B300D0C796 /* Debug */ = {
781 | isa = XCBuildConfiguration;
782 | baseConfigurationReference = AA0AB43F661D32464E4E23C4 /* Pods-reactorkitKeyboardExample.debug.xcconfig */;
783 | buildSettings = {
784 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
785 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
786 | CODE_SIGN_ENTITLEMENTS = reactorkitKeyboardExample/reactorkitKeyboardExample.entitlements;
787 | CODE_SIGN_STYLE = Automatic;
788 | DEVELOPMENT_TEAM = U6GQL8JQMT;
789 | INFOPLIST_FILE = reactorkitKeyboardExample/Info.plist;
790 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
791 | LD_RUNPATH_SEARCH_PATHS = (
792 | "$(inherited)",
793 | "@executable_path/Frameworks",
794 | );
795 | PRODUCT_BUNDLE_IDENTIFIER = com.tmsae.reactorkitKeyboardExample;
796 | PRODUCT_NAME = "$(TARGET_NAME)";
797 | SWIFT_VERSION = 5.0;
798 | TARGETED_DEVICE_FAMILY = "1,2";
799 | };
800 | name = Debug;
801 | };
802 | ED8A0185244E03B300D0C796 /* Release */ = {
803 | isa = XCBuildConfiguration;
804 | baseConfigurationReference = 2038FF17147E219B043ABEAB /* Pods-reactorkitKeyboardExample.release.xcconfig */;
805 | buildSettings = {
806 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
807 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
808 | CODE_SIGN_ENTITLEMENTS = reactorkitKeyboardExample/reactorkitKeyboardExample.entitlements;
809 | CODE_SIGN_STYLE = Automatic;
810 | DEVELOPMENT_TEAM = U6GQL8JQMT;
811 | INFOPLIST_FILE = reactorkitKeyboardExample/Info.plist;
812 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
813 | LD_RUNPATH_SEARCH_PATHS = (
814 | "$(inherited)",
815 | "@executable_path/Frameworks",
816 | );
817 | PRODUCT_BUNDLE_IDENTIFIER = com.tmsae.reactorkitKeyboardExample;
818 | PRODUCT_NAME = "$(TARGET_NAME)";
819 | SWIFT_VERSION = 5.0;
820 | TARGETED_DEVICE_FAMILY = "1,2";
821 | };
822 | name = Release;
823 | };
824 | EDED22BF244E09E6004503BB /* Debug */ = {
825 | isa = XCBuildConfiguration;
826 | baseConfigurationReference = 6BC67B005AA82AFD5DBBB4B5 /* Pods-keyboard.debug.xcconfig */;
827 | buildSettings = {
828 | CODE_SIGN_ENTITLEMENTS = keyboard/keyboard.entitlements;
829 | CODE_SIGN_STYLE = Automatic;
830 | DEVELOPMENT_TEAM = U6GQL8JQMT;
831 | INFOPLIST_FILE = keyboard/Info.plist;
832 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
833 | LD_RUNPATH_SEARCH_PATHS = (
834 | "$(inherited)",
835 | "@executable_path/Frameworks",
836 | "@executable_path/../../Frameworks",
837 | );
838 | PRODUCT_BUNDLE_IDENTIFIER = com.tmsae.reactorkitKeyboardExample.keyboard;
839 | PRODUCT_NAME = "$(TARGET_NAME)";
840 | SKIP_INSTALL = YES;
841 | SWIFT_VERSION = 5.0;
842 | TARGETED_DEVICE_FAMILY = "1,2";
843 | };
844 | name = Debug;
845 | };
846 | EDED22C0244E09E6004503BB /* Release */ = {
847 | isa = XCBuildConfiguration;
848 | baseConfigurationReference = 6AFD01CE0785D20809E99E2B /* Pods-keyboard.release.xcconfig */;
849 | buildSettings = {
850 | CODE_SIGN_ENTITLEMENTS = keyboard/keyboard.entitlements;
851 | CODE_SIGN_STYLE = Automatic;
852 | DEVELOPMENT_TEAM = U6GQL8JQMT;
853 | INFOPLIST_FILE = keyboard/Info.plist;
854 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
855 | LD_RUNPATH_SEARCH_PATHS = (
856 | "$(inherited)",
857 | "@executable_path/Frameworks",
858 | "@executable_path/../../Frameworks",
859 | );
860 | PRODUCT_BUNDLE_IDENTIFIER = com.tmsae.reactorkitKeyboardExample.keyboard;
861 | PRODUCT_NAME = "$(TARGET_NAME)";
862 | SKIP_INSTALL = YES;
863 | SWIFT_VERSION = 5.0;
864 | TARGETED_DEVICE_FAMILY = "1,2";
865 | };
866 | name = Release;
867 | };
868 | /* End XCBuildConfiguration section */
869 |
870 | /* Begin XCConfigurationList section */
871 | ED8A016A244E03B100D0C796 /* Build configuration list for PBXProject "reactorkitKeyboardExample" */ = {
872 | isa = XCConfigurationList;
873 | buildConfigurations = (
874 | ED8A0181244E03B300D0C796 /* Debug */,
875 | ED8A0182244E03B300D0C796 /* Release */,
876 | );
877 | defaultConfigurationIsVisible = 0;
878 | defaultConfigurationName = Release;
879 | };
880 | ED8A0183244E03B300D0C796 /* Build configuration list for PBXNativeTarget "reactorkitKeyboardExample" */ = {
881 | isa = XCConfigurationList;
882 | buildConfigurations = (
883 | ED8A0184244E03B300D0C796 /* Debug */,
884 | ED8A0185244E03B300D0C796 /* Release */,
885 | );
886 | defaultConfigurationIsVisible = 0;
887 | defaultConfigurationName = Release;
888 | };
889 | EDED22BE244E09E6004503BB /* Build configuration list for PBXNativeTarget "keyboard" */ = {
890 | isa = XCConfigurationList;
891 | buildConfigurations = (
892 | EDED22BF244E09E6004503BB /* Debug */,
893 | EDED22C0244E09E6004503BB /* Release */,
894 | );
895 | defaultConfigurationIsVisible = 0;
896 | defaultConfigurationName = Release;
897 | };
898 | /* End XCConfigurationList section */
899 | };
900 | rootObject = ED8A0167244E03B100D0C796 /* Project object */;
901 | }
902 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/project.xcworkspace/xcuserdata/fernando.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample.xcodeproj/project.xcworkspace/xcuserdata/fernando.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/xcshareddata/xcschemes/keyboard.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
16 |
22 |
23 |
24 |
30 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
47 |
48 |
60 |
64 |
65 |
66 |
72 |
73 |
74 |
75 |
82 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/xcshareddata/xcschemes/reactorkitKeyboardExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcodeproj/xcuserdata/fernando.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | keyboard.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 15
11 |
12 | reactorkitKeyboardExample.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 16
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | ED8A016E244E03B100D0C796
21 |
22 | primary
23 |
24 |
25 | EDED22B5244E09E6004503BB
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcworkspace/xcuserdata/fernando.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample.xcworkspace/xcuserdata/fernando.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/reactorkitKeyboardExample.xcworkspace/xcuserdata/fernando.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 |
19 |
20 | let reactor = MainViewReactor()
21 | let controller = MainViewController(reactor: reactor)
22 | let navigationController = BaseNavigationController(rootViewController: controller)
23 |
24 | window?.rootViewController = navigationController
25 | window?.makeKeyAndVisible()
26 |
27 | return true
28 | }
29 |
30 | func applicationWillResignActive(_ application: UIApplication) {
31 | // 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.
32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
33 | }
34 |
35 | func applicationDidEnterBackground(_ application: UIApplication) {
36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
38 | }
39 |
40 | func applicationWillEnterForeground(_ application: UIApplication) {
41 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
42 | }
43 |
44 | func applicationDidBecomeActive(_ application: UIApplication) {
45 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
46 | }
47 |
48 | func applicationWillTerminate(_ application: UIApplication) {
49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Base/BaseNavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseNavigationController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class BaseNavigationController: UINavigationController {
12 |
13 | lazy private(set) var className: String = {
14 | return type(of: self).description().components(separatedBy: ".").last ?? ""
15 | }()
16 |
17 | // MARK: - Properties
18 |
19 | // MARK: - Initialize
20 |
21 | // MARK: Rx
22 |
23 | // MARK: - Life Cycle
24 |
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 | self.navigationBar.prefersLargeTitles = true
28 | self.navigationBar.largeTitleTextAttributes = [
29 | NSAttributedString.Key.foregroundColor: Color.title
30 | ]
31 | }
32 |
33 | deinit {
34 | logger.verbose("DEINIT: \(self.className)")
35 | }
36 |
37 | // MARK: - Layout Constraints
38 |
39 | // MARK: - Configure
40 | }
41 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Base/BaseTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseTableViewCell.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RxSwift
11 |
12 | class BaseTableViewCell: UITableViewCell {
13 |
14 | private(set) var didSetupConstraints = false
15 |
16 | var disposeBag = DisposeBag()
17 |
18 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
19 | super.init(style: style, reuseIdentifier: reuseIdentifier)
20 | self.addViews()
21 | self.layoutSubviews()
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | override func layoutSubviews() {
29 | if !self.didSetupConstraints {
30 | self.setupConstraints()
31 | self.didSetupConstraints = true
32 | }
33 | super.layoutSubviews()
34 | }
35 |
36 | func addViews() {}
37 |
38 | func setupConstraints() {}
39 | }
40 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Base/BaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import SnapKit
12 | import Then
13 | import ReusableKit
14 | import RxSwift
15 | import RxCocoa
16 |
17 | class BaseViewController: UIViewController {
18 |
19 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
20 | return .portrait
21 | }
22 |
23 | override var shouldAutorotate: Bool {
24 | return true
25 | }
26 |
27 | override var prefersStatusBarHidden: Bool {
28 | return false
29 | }
30 |
31 | override var preferredStatusBarStyle: UIStatusBarStyle {
32 | return .lightContent
33 | }
34 |
35 | var disposeBag = DisposeBag()
36 |
37 | lazy private(set) var className: String = {
38 | return type(of: self).description().components(separatedBy: ".").last ?? ""
39 | }()
40 |
41 | /// There is a bug when trying to go back to previous view controller in a navigation controller
42 | /// on iOS 11, a scroll view in the previous screen scrolls weirdly. In order to get this fixed,
43 | /// we have to set the scrollView's `contentInsetAdjustmentBehavior` property to `.never` on
44 | /// `viewWillAppear()` and set back to the original value on `viewDidAppear()`.
45 | private var scrollViewOriginalContentInsetAdjustmentBehaviorRawValue: Int?
46 |
47 | init() {
48 | super.init(nibName: nil, bundle: nil)
49 | }
50 |
51 | required convenience init?(coder aDecoder: NSCoder) {
52 | self.init()
53 | }
54 |
55 | deinit {
56 | print("DEINIT: \(self.className)")
57 | }
58 |
59 | var safeAreaInsets: UIEdgeInsets {
60 | get {
61 | if #available(iOS 11.0, *) {
62 | guard let window = UIApplication.shared.windows.first else { return self.view.safeAreaInsets }
63 | return window.safeAreaInsets
64 | } else {
65 | return .zero
66 | }
67 | }
68 | }
69 |
70 | // MARK: View Lifecycle
71 | override func viewDidLoad() {
72 | super.viewDidLoad()
73 | self.view.backgroundColor = .white
74 |
75 | self.addViews()
76 | self.view.setNeedsUpdateConstraints()
77 |
78 | }
79 |
80 | override func viewWillAppear(_ animated: Bool) {
81 | super.viewWillAppear(animated)
82 | }
83 |
84 | override func viewDidAppear(_ animated: Bool) {
85 | super.viewDidAppear(animated)
86 | }
87 |
88 | // MARK: add Views,Layout Constraints
89 | private(set) var didSetupConstraints = false
90 |
91 | override func updateViewConstraints() {
92 | if !self.didSetupConstraints {
93 | self.setupConstraints()
94 | self.didSetupConstraints = true
95 | }
96 | super.updateViewConstraints()
97 | }
98 |
99 | func addViews() {}
100 |
101 | func setupConstraints() {
102 | // Override point
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Common/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Constants {
12 | enum AppConfig {
13 | static let groupID = "group.com.tmsae.keyboardExample"
14 | static let oldUserDefaultKey = "kWords"
15 | }
16 |
17 | enum ETC {
18 | static let repoURL = "https://github.com/techinpark/reactorkit-keyboard-example"
19 | }
20 | }
21 |
22 |
23 | // MARK: Web Links
24 | enum WebLinks {
25 | static let keyboardUseageURL = "https://www.notion.so/3024c4472caf459b97eb1b90fce49a26"
26 | static let keyboardUsageEngURL = "https://www.notion.so/How-to-use-PasteKeyboard-17694e8ade094b61ac9a2c5c2e6b43db"
27 | static let updateLogsURL = ""
28 | static let paymentPageForKor = "http://tmsae.kr/payment/donate.html"
29 | static let kakaoChat = "https://open.kakao.com/o/sWy6qMYb"
30 | static let SurveyFormGoogle = "https://forms.gle/28q5b7JMgXEwEeGt7"
31 | static let paymentPageForGlobal = "https://www.buymeacoffee.com/n93O2fZ"
32 | }
33 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Common/GlobalColors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GlobalColors.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct Color {
12 | static let title: UIColor = {
13 | if #available(iOS 13, *) {
14 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
15 | if UITraitCollection.userInterfaceStyle == .dark {
16 | // Return color for Dark Mode
17 | return .white
18 | } else {
19 | // Return color for Light Mode
20 | return .black
21 | }
22 | }
23 | } else {
24 | // Return fallback color for iOS 12 and lower
25 | return .black
26 | }
27 | }()
28 |
29 | static let description: UIColor = {
30 | if #available(iOS 13, *) {
31 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
32 | if UITraitCollection.userInterfaceStyle == .dark {
33 | // Return color for Dark Mode
34 | return .gray
35 | } else {
36 | // Return color for Light Mode
37 | return .gray
38 | }
39 | }
40 | } else {
41 | // Return fallback color for iOS 12 and lower
42 | return .gray
43 | }
44 | }()
45 |
46 |
47 |
48 |
49 | static let background: UIColor = {
50 | if #available(iOS 13, *) {
51 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
52 | if UITraitCollection.userInterfaceStyle == .dark {
53 | // Return color for Dark Mode
54 | return .black
55 | } else {
56 | // Return color for Light Mode
57 | return .white
58 | }
59 | }
60 | } else {
61 | // Return fallback color for iOS 12 and lower
62 | return .white
63 | }
64 | }()
65 |
66 | static let textColor: UIColor = {
67 | if #available(iOS 13, *) {
68 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
69 | if UITraitCollection.userInterfaceStyle == .dark {
70 | // Return color for Dark Mode
71 | return .white
72 | } else {
73 | // Return color for Light Mode
74 | return .black
75 | }
76 | }
77 | } else {
78 | // Return fallback color for iOS 12 and lower
79 | return .black
80 | }
81 | }()
82 |
83 | static let red: UIColor = {
84 | if #available(iOS 13, *) {
85 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
86 | if UITraitCollection.userInterfaceStyle == .dark {
87 | // Return color for Dark Mode
88 | return UIColor.init(red: 248, green: 44, blue: 84, alpha: 1.0)
89 | } else {
90 | // Return color for Light Mode
91 | return UIColor.init(red: 248, green: 7, blue: 63, alpha: 1.0)
92 | }
93 | }
94 | } else {
95 | // Return fallback color for iOS 12 and lower
96 | return UIColor.init(red: 248, green: 7, blue: 63, alpha: 1.0)
97 | }
98 | }()
99 |
100 | static let keySpaceBackground: UIColor = {
101 | if #available(iOS 13, *) {
102 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
103 | if UITraitCollection.userInterfaceStyle == .dark {
104 | // Return color for Dark Mode
105 | return UIColor(red: 106, green: 106, blue: 106)
106 | } else {
107 | // Return color for Light Mode
108 | return .white
109 | }
110 | }
111 | } else {
112 | // Return fallback color for iOS 12 and lower
113 | return .white
114 | }
115 | }()
116 |
117 | static let keyBackground: UIColor = {
118 | if #available(iOS 13, *) {
119 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
120 | if UITraitCollection.userInterfaceStyle == .dark {
121 | // Return color for Dark Mode
122 | return UIColor(red: 71, green: 71, blue: 71)
123 | } else {
124 | // Return color for Light Mode
125 | return UIColor(red: 180, green: 184, blue: 192)
126 | }
127 | }
128 | } else {
129 | // Return fallback color for iOS 12 and lower
130 | return UIColor(red: 180, green: 184, blue: 192)
131 | }
132 | }()
133 |
134 | static let keyboardBackground: UIColor = {
135 | if #available(iOS 13, *) {
136 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
137 | if UITraitCollection.userInterfaceStyle == .dark {
138 | // Return color for Dark Mode
139 | return UIColor(red: 43, green: 43, blue: 43)
140 | } else {
141 | // Return color for Light Mode
142 | return UIColor(red: 214, green: 216, blue: 221)
143 | }
144 | }
145 | } else {
146 | // Return fallback color for iOS 12 and lower
147 | return UIColor(red: 214, green: 216, blue: 221)
148 | }
149 | }()
150 |
151 | static let keyboardListBackground: UIColor = {
152 | if #available(iOS 13, *) {
153 | return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
154 | if UITraitCollection.userInterfaceStyle == .dark {
155 | // Return color for Dark Mode
156 | return UIColor(red: 43, green: 43, blue: 43)
157 | } else {
158 | // Return color for Light Mode
159 | return .white
160 | }
161 | }
162 | } else {
163 | // Return fallback color for iOS 12 and lower
164 | return .white
165 | }
166 | }()
167 | }
168 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Common/UIColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | extension UIColor {
11 | convenience init(red: Int, green: Int, blue: Int) {
12 | assert(red >= 0 && red <= 255, "Invalid red component")
13 | assert(green >= 0 && green <= 255, "Invalid green component")
14 | assert(blue >= 0 && blue <= 255, "Invalid blue component")
15 | self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
16 | }
17 |
18 | convenience init(netHex:Int) {
19 | self.init(red:(netHex >> 16) & 0xff, green:(netHex >> 8) & 0xff, blue:netHex & 0xff)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Common/Utillity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utillity.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class Utility {
13 |
14 | static let shared = Utility()
15 | private let userDefaults = UserDefaults.standard
16 |
17 | func getWords() -> [String] {
18 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return [] }
19 | if let data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
20 | return data
21 | }
22 |
23 | return []
24 | }
25 |
26 | func getIndex(text: String) -> Int {
27 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return -1 }
28 | if let data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
29 | if let index = data.firstIndex(of: text) {
30 | return index
31 | }
32 | }
33 |
34 | return -1
35 | }
36 |
37 | func updateWord(index: Int, text:String) -> Bool {
38 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return false }
39 | if var data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
40 | data.remove(at: index)
41 | data.insert(text, at: index)
42 | userDefault.set(data, forKey: Constants.AppConfig.oldUserDefaultKey)
43 | userDefault.synchronize()
44 | return true
45 | }
46 |
47 | return false
48 | }
49 |
50 | func moveWords(source: Int, destination: Int) -> Bool {
51 |
52 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return false }
53 | if let original = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
54 | var copy = original
55 | copy.remove(at: source)
56 | copy.insert(original[source], at: destination)
57 | userDefault.set(copy, forKey: Constants.AppConfig.oldUserDefaultKey)
58 | userDefault.synchronize()
59 |
60 | return true
61 | }
62 |
63 | return false
64 | }
65 |
66 | func deleteWord(index: Int) -> Bool {
67 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return false }
68 | if var data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
69 | data.remove(at: index)
70 | userDefault.set(data, forKey: Constants.AppConfig.oldUserDefaultKey)
71 | userDefault.synchronize()
72 | return true
73 | }
74 |
75 | return false
76 | }
77 |
78 | func saveWord(text: String) -> Bool {
79 | guard let userDefault = UserDefaults(suiteName: Constants.AppConfig.groupID) else { return false }
80 | if var data = userDefault.array(forKey: Constants.AppConfig.oldUserDefaultKey) as? [String] {
81 | data.append(text)
82 | userDefault.set(data, forKey: Constants.AppConfig.oldUserDefaultKey)
83 | userDefault.synchronize()
84 | return true
85 | } else {
86 | let array:[String] = [text]
87 | userDefault.set(array, forKey: Constants.AppConfig.oldUserDefaultKey)
88 | userDefault.synchronize()
89 | return true
90 | }
91 | }
92 |
93 | class func sharedInstance() -> Utility {
94 | return shared
95 | }
96 |
97 | func setBool(value: Bool, key: String) {
98 | userDefaults.set(value, forKey: key)
99 | userDefaults.synchronize()
100 | }
101 |
102 | func getBool(key: String) -> Bool {
103 | return userDefaults.bool(forKey: key)
104 | }
105 |
106 | func setInt(value:Int, key: String) {
107 | userDefaults.set(value, forKey: key)
108 | userDefaults.synchronize()
109 | }
110 |
111 | func getInt(key: String) -> Int {
112 | return userDefaults.integer(forKey: key)
113 | }
114 |
115 | func removeObject(key: String) {
116 | userDefaults.removeObject(forKey: key)
117 | userDefaults.synchronize()
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Extensions/Rx/UITableView+Rx.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+Rx.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import RxCocoa
10 | import RxDataSources
11 | import RxSwift
12 |
13 | extension Reactive where Base: UITableView {
14 | func itemSelected(dataSource: TableViewSectionedDataSource) -> ControlEvent {
15 | let source = self.itemSelected.map { indexPath in
16 | dataSource[indexPath]
17 | }
18 | return ControlEvent(events: source)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Logging/Logger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Logger.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CocoaLumberjack
11 | import Then
12 |
13 | extension DDLogFlag {
14 | public var level: String {
15 | switch self {
16 | case DDLogFlag.error: return "🚫 ERROR"
17 | case DDLogFlag.warning: return "⚠️ WARNING"
18 | case DDLogFlag.info: return "✅ INFO"
19 | case DDLogFlag.debug: return "🐛 DEBUG"
20 | case DDLogFlag.verbose: return "💙 VERBOSE"
21 | default: return "☠️ UNKNOWN"
22 | }
23 | }
24 | }
25 |
26 | private class LogFormatter: NSObject, DDLogFormatter {
27 |
28 | static let dateFormatter = DateFormatter().then {
29 | $0.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
30 | }
31 |
32 | public func format(message logMessage: DDLogMessage) -> String? {
33 | let timestamp = LogFormatter.dateFormatter.string(from: logMessage.timestamp)
34 | let level = logMessage.flag.level
35 | let filename = logMessage.fileName
36 | let function = logMessage.function ?? ""
37 | let line = logMessage.line
38 | let message = logMessage.message.components(separatedBy: "\n").joined(separator: "\n ")
39 | return "\(timestamp) \(level) \(filename).\(function):\(line) - \(message)"
40 | }
41 |
42 | private func formattedDate(from date: Date) -> String {
43 | return LogFormatter.dateFormatter.string(from: date)
44 | }
45 | }
46 |
47 | /// A shared instance of `Logger`.
48 | let logger = Logger()
49 |
50 | final class Logger {
51 |
52 | // MARK: Initialize
53 |
54 | init() {
55 | setenv("XcodeColors", "YES", 0)
56 |
57 | // TTY = Xcode console
58 | DDTTYLogger.sharedInstance?.do {
59 | $0.logFormatter = LogFormatter()
60 | $0.colorsEnabled = false /* true */ // Note: doesn't work in Xcode 8
61 | $0.setForegroundColor(DDMakeColor(30, 121, 214), backgroundColor: nil, for: .info)
62 | $0.setForegroundColor(DDMakeColor(50, 143, 72), backgroundColor: nil, for: .debug)
63 | DDLog.add($0)
64 | }
65 |
66 | // File logger
67 | DDFileLogger().do {
68 | $0.rollingFrequency = TimeInterval(60 * 60 * 24) // 24 hours
69 | $0.logFileManager.maximumNumberOfLogFiles = 7
70 | DDLog.add($0)
71 | }
72 | }
73 |
74 | // MARK: Logging
75 | func error(
76 | _ items: Any...,
77 | file: StaticString = #file,
78 | function: StaticString = #function,
79 | line: UInt = #line
80 | ) {
81 | let message = self.message(from: items)
82 | DDLogError(message, file: file, function: function, line: line)
83 | }
84 |
85 | func warning(
86 | _ items: Any...,
87 | file: StaticString = #file,
88 | function: StaticString = #function,
89 | line: UInt = #line
90 | ) {
91 | let message = self.message(from: items)
92 | DDLogWarn(message, file: file, function: function, line: line)
93 | }
94 |
95 | func info(
96 | _ items: Any...,
97 | file: StaticString = #file,
98 | function: StaticString = #function,
99 | line: UInt = #line
100 | ) {
101 | let message = self.message(from: items)
102 | DDLogInfo(message, file: file, function: function, line: line)
103 | }
104 |
105 | func debug(
106 | _ items: Any...,
107 | file: StaticString = #file,
108 | function: StaticString = #function,
109 | line: UInt = #line
110 | ) {
111 | let message = self.message(from: items)
112 | DDLogDebug(message, file: file, function: function, line: line)
113 | }
114 |
115 | func verbose(
116 | _ items: Any...,
117 | file: StaticString = #file,
118 | function: StaticString = #function,
119 | line: UInt = #line
120 | ) {
121 | let message = self.message(from: items)
122 | DDLogVerbose(message, file: file, function: function, line: line)
123 | }
124 |
125 | // MARK: Utils
126 |
127 | private func message(from items: [Any]) -> String {
128 | return items
129 | .map { String(describing: $0) }
130 | .joined(separator: " ")
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Sections/MainSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainSection.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import RxDataSources
11 |
12 | enum MainSection {
13 | case list([MainSectionItem])
14 | }
15 |
16 | extension MainSection: SectionModelType {
17 |
18 | typealias Identify = String
19 | typealias Item = MainSectionItem
20 | var identify: String {
21 | return ""
22 | }
23 |
24 | var items: [MainSectionItem] {
25 | switch self {
26 | case .list(let items):
27 | return items
28 | }
29 | }
30 |
31 | init(original: MainSection, items: [Item]) {
32 | switch original {
33 | case .list:
34 | self = .list(items)
35 | }
36 | }
37 | }
38 |
39 | enum MainSectionItem {
40 | case listItem(MainTableViewCellReactor)
41 | }
42 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Sections/SettingSection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSection.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import RxDataSources
10 |
11 | enum SettingSection {
12 | case usage([SettingSectionItem])
13 | }
14 |
15 | extension SettingSection: SectionModelType {
16 |
17 | var items: [SettingSectionItem] {
18 | switch self {
19 | case .usage(let items):
20 | return items
21 | }
22 | }
23 |
24 | init(original: SettingSection, items: [SettingSectionItem]) {
25 | switch original {
26 | case .usage:
27 | self = .usage(items)
28 | }
29 | }
30 | }
31 |
32 | enum SettingSectionItem {
33 | case openSource(SettingCellReactor)
34 | case githubRepo(SettingCellReactor)
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Icon-App-20x20@2x.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "Icon-App-20x20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "Icon-App-29x29@1x.png",
17 | "idiom" : "iphone",
18 | "scale" : "1x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "Icon-App-29x29@2x.png",
23 | "idiom" : "iphone",
24 | "scale" : "2x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "Icon-App-29x29@3x.png",
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "29x29"
32 | },
33 | {
34 | "filename" : "Icon-App-40x40@2x.png",
35 | "idiom" : "iphone",
36 | "scale" : "2x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "Icon-App-40x40@3x.png",
41 | "idiom" : "iphone",
42 | "scale" : "3x",
43 | "size" : "40x40"
44 | },
45 | {
46 | "filename" : "Icon-App-60x60@2x.png",
47 | "idiom" : "iphone",
48 | "scale" : "2x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "Icon-App-60x60@3x.png",
53 | "idiom" : "iphone",
54 | "scale" : "3x",
55 | "size" : "60x60"
56 | },
57 | {
58 | "filename" : "Icon-App-20x20@1x.png",
59 | "idiom" : "ipad",
60 | "scale" : "1x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "Icon-App-20x20@2x.png",
65 | "idiom" : "ipad",
66 | "scale" : "2x",
67 | "size" : "20x20"
68 | },
69 | {
70 | "filename" : "Icon-App-29x29@1x.png",
71 | "idiom" : "ipad",
72 | "scale" : "1x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "Icon-App-29x29@2x.png",
77 | "idiom" : "ipad",
78 | "scale" : "2x",
79 | "size" : "29x29"
80 | },
81 | {
82 | "filename" : "Icon-App-40x40@1x.png",
83 | "idiom" : "ipad",
84 | "scale" : "1x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "Icon-App-40x40@2x.png",
89 | "idiom" : "ipad",
90 | "scale" : "2x",
91 | "size" : "40x40"
92 | },
93 | {
94 | "filename" : "Icon-App-76x76@1x.png",
95 | "idiom" : "ipad",
96 | "scale" : "1x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "Icon-App-76x76@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "76x76"
104 | },
105 | {
106 | "filename" : "Icon-App-83.5x83.5@2x.png",
107 | "idiom" : "ipad",
108 | "scale" : "2x",
109 | "size" : "83.5x83.5"
110 | },
111 | {
112 | "filename" : "ItunesArtwork@2x.png",
113 | "idiom" : "ios-marketing",
114 | "scale" : "1x",
115 | "size" : "1024x1024"
116 | },
117 | {
118 | "filename" : "Icon-App-76x76@2x.png",
119 | "idiom" : "iphone",
120 | "scale" : "2x",
121 | "size" : "76x76"
122 | }
123 | ],
124 | "info" : {
125 | "author" : "xcode",
126 | "version" : 1
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "clipboard@1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "clipboard@1x-1.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "clipboard@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "clipboard@2x-1.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "filename" : "clipboard@3x.png",
37 | "idiom" : "universal",
38 | "scale" : "3x"
39 | },
40 | {
41 | "appearances" : [
42 | {
43 | "appearance" : "luminosity",
44 | "value" : "dark"
45 | }
46 | ],
47 | "filename" : "clipboard@3x-1.png",
48 | "idiom" : "universal",
49 | "scale" : "3x"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@1x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@1x-1.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@2x-1.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@3x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@3x-1.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/clipboard.imageset/clipboard@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "delete@1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "delete_white@1x.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "delete@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "delete_white@2x.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "filename" : "delete@3x.png",
37 | "idiom" : "universal",
38 | "scale" : "3x"
39 | },
40 | {
41 | "appearances" : [
42 | {
43 | "appearance" : "luminosity",
44 | "value" : "dark"
45 | }
46 | ],
47 | "filename" : "delete_white@3x.png",
48 | "idiom" : "universal",
49 | "scale" : "3x"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/delete.imageset/delete_white@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "global@1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "global-white@1x.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "global@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "global-white@2x.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "filename" : "global@3x.png",
37 | "idiom" : "universal",
38 | "scale" : "3x"
39 | },
40 | {
41 | "appearances" : [
42 | {
43 | "appearance" : "luminosity",
44 | "value" : "dark"
45 | }
46 | ],
47 | "filename" : "global-white@3x.png",
48 | "idiom" : "universal",
49 | "scale" : "3x"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global-white@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/global.imageset/global@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "plus.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "plus@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "plus@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/plus.imageset/plus@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "return@1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "return-white@1x.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "return@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "return-white@2x.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "filename" : "return@3x.png",
37 | "idiom" : "universal",
38 | "scale" : "3x"
39 | },
40 | {
41 | "appearances" : [
42 | {
43 | "appearance" : "luminosity",
44 | "value" : "dark"
45 | }
46 | ],
47 | "filename" : "return-white@3x.png",
48 | "idiom" : "universal",
49 | "scale" : "3x"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return-white@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@1x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@2x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techinpark/reactorkit-keyboard-example/26d215b5832750fb5c347dca2d7ac3a954b279f0/reactorkitKeyboardExample/Supported Files/Assets.xcassets/return.imageset/return@3x.png
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /*
2 | InfoPlist.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 | "CFBundleDisplayName" = "Keyboard-Example";
9 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 |
9 | // WriteViewController
10 | "paste_alert_title" = "Notice";
11 | "paste_alert_body" = "Detect Message in Clipboard";
12 | "paste_alert_okay_button" = "Paste";
13 | "paste_alert_cancel_button" = "Cancel";
14 | "paste_alert_message" = "New Message Added sucessfully";
15 | "write_title" = "Add New";
16 |
17 | // SettingViewController
18 | "setting_title" = "Settings";
19 | "edit_title" = "Edit";
20 | "opensource_title" = "Open Source License";
21 | "github_repo_title" = "Go to Github Repository";
22 | "opensource_comment" = "Thanks for clone this project 🚀";
23 | // Common Messages
24 | "app_title" = "Keyboard-Example";
25 | "common_ok" = "Okay";
26 | "common_loading" = "Loading";
27 | "common_close" = "Close";
28 | "common_save" = "Save";
29 | "common_load_data" = "Sync Saved Data";
30 | "message_list_empty" = "Now List is Empty.";
31 |
32 | // Keyboard
33 | "space" = "space";
34 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/ko.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /*
2 | InfoPlist.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 | "CFBundleDisplayName" = "Keyboard-Example";
9 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Supported Files/ko.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | reactorkitKeyboardExample
4 |
5 | Created by Fernando on 2020/04/21.
6 | Copyright © 2020 tmsae. All rights reserved.
7 | */
8 |
9 | // WriteViewController
10 | "paste_alert_title" = "알림";
11 | "paste_alert_body" = "클립보드에 내용이 감지 되었습니다.";
12 | "paste_alert_okay_button" = "붙이기";
13 | "paste_alert_cancel_button" = "취소하기";
14 | "paste_alert_message" = "정상적으로 추가되었습니다";
15 | "write_title" = "추가하기";
16 |
17 | // SettingViewController
18 | "setting_title" = "설정";
19 | "edit_title" = "편집";
20 | "opensource_title" = "오픈소스 라이센스";
21 | "github_repo_title" = "Github 레포지토리로 이동";
22 | "opensource_comment" = "해당 예제를 clone 받아주셔서 감사합니다. 🚀";
23 |
24 | // Common Messages
25 | "app_title" = "Keyboard-Example";
26 | "common_ok" = "확인";
27 | "common_loading" = "로딩중";
28 | "common_close" = "닫기";
29 | "common_save" = "저장";
30 | "common_load_data" = "데이터 불러오기";
31 | "message_list_empty" = "리스트가 비어있습니다 내용을 추가해주세요.";
32 |
33 | // Keyboard
34 | "space" = "space";
35 |
36 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Types/SettingFooterType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingFooterType.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum SettingFooterType: Int {
12 | case dataComment
13 |
14 | var description: String {
15 | switch self {
16 | case .dataComment:
17 | return NSLocalizedString("opensource_comment", comment: "")
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Types/SettingMenuTypes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingMenuTypes.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum SettingMenuTypes {
12 | case openSource
13 | case githubRepo
14 |
15 | var title: String {
16 | switch self {
17 | case .openSource:
18 | return NSLocalizedString("opensource_title", comment: "Open Source License")
19 | case .githubRepo:
20 | return NSLocalizedString("github_repo_title", comment: "Go to Github Repository")
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view.
16 | }
17 |
18 |
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/MainViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import ReactorKit
12 | import RxCocoa
13 | import RxDataSources
14 | import RxSwift
15 | import ReusableKit
16 | import RxViewController
17 | import Then
18 |
19 | final class MainViewController: BaseViewController, View {
20 | typealias Reactor = MainViewReactor
21 |
22 | // MARK: Properties
23 |
24 | private struct Metric {
25 | static let writeButtonWidthHeight: CGFloat = 60.0
26 | static let writeButtonMarginLeft: CGFloat = -30.0
27 | static let writeButtonMarginRight: CGFloat = -30.0
28 | static let writeButtonMarginBottom: CGFloat = -20.0
29 | static let writeButtonRadius: CGFloat = 30.0
30 | static let adViewHeight: CGFloat = 60.0
31 | static let adViewRadius: CGFloat = 20.0
32 |
33 | static let emptyImageWidthHeight: CGFloat = 128.0
34 | static let emptyMessageTop: CGFloat = 20.0
35 | static let emptyMessageSize: CGFloat = 14.0
36 |
37 | static let tableViewCellHeight: CGFloat = 55.0
38 | }
39 |
40 | private struct Localized {
41 | static let edit = NSLocalizedString("edit_title", comment: "편집")
42 | static let setting = NSLocalizedString("setting_title", comment: "설정")
43 | static let title = NSLocalizedString("app_title", comment: "복붙키보드")
44 | static let emptyMessage = NSLocalizedString("message_list_empty", comment: "등록된 내용이 없습니다")
45 | }
46 |
47 | private struct Reusable {
48 | static let mainCell = ReusableCell()
49 | }
50 |
51 | // MARK: Initializing
52 |
53 | private let tableView = UITableView().then {
54 | $0.backgroundColor = Color.background
55 | $0.rowHeight = Metric.tableViewCellHeight
56 | $0.tableHeaderView = UIView(frame: .zero)
57 | $0.tableFooterView = UIView(frame: .zero)
58 |
59 | if #available(iOS 11.0, *) {
60 | $0.contentInsetAdjustmentBehavior = .never
61 | }
62 |
63 | $0.register(Reusable.mainCell)
64 | $0.separatorStyle = .singleLine
65 | $0.separatorInset.left = 0
66 | }
67 |
68 | private let writeButton = UIButton().then {
69 | $0.backgroundColor = .red
70 | $0.layer.masksToBounds = true
71 | $0.layer.cornerRadius = Metric.writeButtonRadius
72 | $0.setImage(#imageLiteral(resourceName: "plus"), for: .normal)
73 | }
74 |
75 | private let emptyView = UIView().then {
76 | $0.backgroundColor = Color.background
77 | $0.isHidden = true
78 | }
79 |
80 | private let emptyImageView = UIImageView().then {
81 | $0.image = #imageLiteral(resourceName: "clipboard")
82 | }
83 |
84 | private let emptyMessageLabel = UILabel().then {
85 | $0.text = Localized.emptyMessage
86 | $0.font = UIFont.systemFont(ofSize: Metric.emptyMessageSize)
87 | $0.textColor = Color.description
88 | $0.sizeToFit()
89 | }
90 |
91 |
92 | private let leftBarButtonItem = UIBarButtonItem(title: Localized.edit, style: .plain, target: nil, action: nil)
93 | private let rightBarButtonItem = UIBarButtonItem(title: Localized.setting, style: .plain, target: nil, action: nil)
94 | private var dataSource: RxTableViewSectionedReloadDataSource?
95 |
96 | convenience override init() {
97 | let reactor = MainViewReactor()
98 | self.init(reactor: reactor)
99 | }
100 |
101 | init(reactor: MainViewReactor) {
102 | defer { self.reactor = reactor }
103 | super.init()
104 | self.dataSource = self.dataSourceFactory()
105 | }
106 |
107 | required init?(coder _: NSCoder) {
108 | fatalError("init(coder:) has not been implemented")
109 | }
110 |
111 | // MARK: View Life Cycle
112 |
113 | override func viewDidLoad() {
114 | super.viewDidLoad()
115 | logger.debug("viewDidLoad")
116 | }
117 |
118 | override func viewWillAppear(_ animated: Bool) {
119 | super.viewWillAppear(animated)
120 | logger.debug("viewWillAppear")
121 | }
122 |
123 | override func addViews() {
124 | super.addViews()
125 | self.setupView()
126 | }
127 |
128 | private func setupView() {
129 |
130 |
131 | self.view.backgroundColor = Color.background
132 | self.navigationItem.leftBarButtonItem = leftBarButtonItem
133 | self.navigationItem.rightBarButtonItem = rightBarButtonItem
134 |
135 | self.emptyView.addSubview(emptyImageView)
136 | self.emptyView.addSubview(emptyMessageLabel)
137 |
138 |
139 | self.view.addSubview(tableView)
140 | self.view.addSubview(emptyView)
141 | self.view.addSubview(writeButton)
142 | }
143 |
144 | override func setupConstraints() {
145 | super.setupConstraints()
146 |
147 |
148 | tableView.snp.makeConstraints { (make) in
149 | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.topMargin)
150 | make.left.right.equalToSuperview()
151 | make.bottom.equalToSuperview()
152 | }
153 |
154 | writeButton.snp.makeConstraints { make in
155 | make.right.equalTo(Metric.writeButtonMarginRight)
156 | make.width.height.equalTo(Metric.writeButtonWidthHeight)
157 | make.bottom.equalTo(self.tableView.snp.bottom).offset(Metric.writeButtonMarginBottom)
158 | }
159 |
160 | emptyView.snp.makeConstraints { (make) in
161 | make.top.equalTo(self.view.safeAreaLayoutGuide.snp.topMargin)
162 | make.left.right.equalToSuperview()
163 | make.bottom.equalToSuperview()
164 | }
165 |
166 | emptyImageView.snp.makeConstraints { (make) in
167 | make.center.equalToSuperview()
168 | }
169 |
170 | emptyMessageLabel.snp.makeConstraints { (make) in
171 | make.top.equalTo(emptyImageView.snp.bottom).offset(Metric.emptyMessageTop)
172 | make.centerX.equalToSuperview()
173 |
174 | }
175 | }
176 |
177 | // MARK: Binding
178 |
179 | func bind(reactor: MainViewReactor) {
180 | // Action
181 | rx.viewDidLoad
182 | .map { Localized.title }
183 | .bind(to: rx.title)
184 | .disposed(by: disposeBag)
185 |
186 |
187 | rx.viewWillAppear
188 | .map { _ in Reactor.Action.loadWords }
189 | .bind(to: reactor.action)
190 | .disposed(by: self.disposeBag)
191 |
192 | leftBarButtonItem.rx.tap
193 | .subscribe(onNext: { [weak self] _ in
194 | guard let self = self else { return }
195 | self.reactor?.action.onNext(.editing)
196 | })
197 | .disposed(by: self.disposeBag)
198 |
199 | rightBarButtonItem.rx.tap
200 | .subscribe(onNext: { [weak self] _ in
201 | guard let self = self else { return }
202 | let reactor = SettingViewReactor()
203 | let settingViewController = SettingViewController(reactor: reactor)
204 | self.navigationController?.pushViewController(settingViewController, animated: true)
205 | })
206 | .disposed(by: disposeBag)
207 |
208 | writeButton.rx.tap
209 | .subscribe(onNext: { [weak self] _ in
210 | guard let self = self else { return }
211 |
212 | let reactor = WriteViewReactor(mode: .write,
213 | text: nil)
214 | let writeViewController = WriteViewController(reactor: reactor)
215 |
216 | let navigationController = UINavigationController(rootViewController: writeViewController)
217 | navigationController.modalPresentationStyle = .fullScreen
218 | self.present(navigationController, animated: true, completion: nil)
219 |
220 | })
221 | .disposed(by: disposeBag)
222 |
223 | // State
224 | reactor.state.map { $0.sections }
225 | .bind(to: tableView.rx.items(dataSource: self.dataSource!))
226 | .disposed(by: self.disposeBag)
227 |
228 | reactor.state.map { !($0.sections.first?.items.isEmpty ?? false) }
229 | .bind(to: leftBarButtonItem.rx.isEnabled)
230 | .disposed(by: self.disposeBag)
231 |
232 | reactor.state.map { $0.sections.first?.items }
233 | .subscribe(onNext: { [weak self] items in
234 | guard let self = self else { return }
235 | if let items = items {
236 | if items.isEmpty {
237 | self.emptyView.isHidden = false
238 | } else {
239 | self.emptyView.isHidden = true
240 | }
241 | }
242 | })
243 | .disposed(by: self.disposeBag)
244 |
245 | reactor.state.map { $0.isEditing }
246 | .distinctUntilChanged()
247 | .subscribe(onNext: { [weak self] isEditing in
248 | guard let self = self else { return }
249 | logger.debug(isEditing)
250 | self.tableView.setEditing(isEditing, animated: true)
251 | })
252 | .disposed(by: self.disposeBag)
253 |
254 | tableView.rx.itemSelected
255 | .subscribe(onNext: { [weak tableView] indexPath in
256 | tableView?.deselectRow(at: indexPath, animated: true)
257 | }).disposed(by: self.disposeBag)
258 |
259 | tableView.rx.itemDeleted
260 | .subscribe(onNext: { [weak self] indexPath in
261 | guard let self = self else { return }
262 | self.reactor?.action.onNext(.deleteWord(indexPath))
263 | logger.debug("item deleted - \(indexPath)")
264 | }).disposed(by: self.disposeBag)
265 |
266 | tableView.rx.itemMoved
267 | .subscribe(onNext: { [weak self] moveItem in
268 | guard let self = self else { return }
269 | self.reactor?.action.onNext(.moveWord(sourceIndex: moveItem.sourceIndex.row,
270 | destinationIndex: moveItem.destinationIndex.row))
271 | logger.debug("item moved - \(moveItem)")
272 | }).disposed(by: self.disposeBag)
273 |
274 | tableView.rx.itemSelected(dataSource: self.dataSource!)
275 | .subscribe(onNext: { [weak self] sectionItem in
276 | guard let self = self else { return }
277 | switch sectionItem {
278 | case let .listItem(cellReactor):
279 | let message = cellReactor.currentState.list.message
280 | let reactor = WriteViewReactor(mode: .edit,
281 | text: message)
282 | let writeViewController = WriteViewController(reactor: reactor)
283 |
284 | let navigationController = UINavigationController(rootViewController: writeViewController)
285 | navigationController.modalPresentationStyle = .fullScreen
286 | self.present(navigationController, animated: true, completion: nil)
287 | }
288 | })
289 | .disposed(by: self.disposeBag)
290 | }
291 |
292 | // MARK: DataSrouceFactory - configuration
293 |
294 | private func dataSourceFactory() -> RxTableViewSectionedReloadDataSource {
295 | return .init(configureCell: { (dataSource, tableView, indexPath, sectionItem) -> UITableViewCell in
296 | switch sectionItem {
297 | case .listItem(let cellReactor):
298 | let cell = tableView.dequeue(Reusable.mainCell, for: indexPath)
299 | cell.reactor = cellReactor
300 | return cell
301 | }
302 | }, canEditRowAtIndexPath: { _, _ in
303 | return true
304 | },
305 | canMoveRowAtIndexPath: { _, _ in
306 | return true
307 | })
308 | }
309 |
310 | }
311 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/MainViewReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 |
10 | import UIKit
11 | import ReactorKit
12 | import RxCocoa
13 | import RxSwift
14 |
15 | final class MainViewReactor: Reactor {
16 |
17 | typealias SectionItem = MainSectionItem
18 |
19 | enum Item {
20 | case word(String)
21 |
22 | var message: String {
23 | switch self {
24 | case let .word(message):
25 | return message
26 | }
27 | }
28 | }
29 |
30 | enum Action {
31 | case loadWords
32 | case copyWord(String)
33 | case setToastMessage(String)
34 | case editing
35 | case moveWord(sourceIndex: Int, destinationIndex: Int)
36 | case deleteWord(IndexPath)
37 | }
38 |
39 | enum Mutation {
40 | case loadWords
41 | case moveWord(sourceIndex: Int, destinationIndex: Int)
42 | case deleteWord(Int)
43 | case setClipboard(String)
44 | case setToastMessage(String)
45 | case editing(Bool)
46 | }
47 |
48 | struct State {
49 |
50 | var words: [String] = []
51 | var toastMessage: String?
52 | var isEditing: Bool = false
53 | var isUpdated: Bool = false
54 | var isMoved: Bool = false
55 |
56 | var sections: [MainSection] {
57 | let sectionItems = words.map { word -> MainTableViewCellReactor in
58 | return MainTableViewCellReactor(list: Item.word(word))
59 | }.map(MainSectionItem.listItem)
60 | return [.list(sectionItems)]
61 | }
62 | }
63 |
64 | let initialState: State
65 | let utility = Utility()
66 | // MARK: Initializing
67 |
68 | init() {
69 | initialState = State()
70 | }
71 |
72 | // MARK: Mutate
73 |
74 | func mutate(action: Action) -> Observable {
75 | switch action {
76 | case .loadWords:
77 | return .just(Mutation.loadWords)
78 | case let .copyWord(word):
79 | return .just(Mutation.setClipboard(word))
80 | case let .setToastMessage(message):
81 | return .just(Mutation.setToastMessage(message))
82 | case .editing:
83 | if false == self.currentState.isEditing {
84 | return .just(Mutation.editing(true))
85 | } else {
86 | return .just(Mutation.editing(false))
87 | }
88 | case let .moveWord(moveEvent):
89 |
90 | let moveWordMutation = Mutation.moveWord(sourceIndex: moveEvent.sourceIndex,
91 | destinationIndex: moveEvent.destinationIndex)
92 |
93 | return .concat([.just(moveWordMutation),
94 | .just(Mutation.loadWords)])
95 |
96 | case let .deleteWord(indexPath):
97 | return .just(.deleteWord(indexPath.row))
98 | }
99 | }
100 |
101 | // MARK: Reduce
102 |
103 | func reduce(state: State, mutation: Mutation) -> State {
104 | var state = state
105 | switch mutation {
106 | case .loadWords:
107 | var originWords = state.words
108 | originWords.removeAll()
109 | originWords = utility.getWords()
110 |
111 | state.words = originWords
112 | return state
113 | case let .moveWord(sourceIndex, destinationIndex):
114 | let isMoved = utility.moveWords(source: sourceIndex,
115 | destination: destinationIndex)
116 | state.isMoved = isMoved
117 | return state
118 | case let .deleteWord(index):
119 | let isUpdated = utility.deleteWord(index: index)
120 | state.isUpdated = isUpdated
121 | state.words = utility.getWords()
122 | return state
123 | case let .setClipboard(word):
124 | self.setPasteboard(string: word)
125 | return state
126 | case let .setToastMessage(message):
127 | state.toastMessage = message
128 | return state
129 | case let .editing(isEditing):
130 | state.isEditing = isEditing
131 | return state
132 |
133 | }
134 | }
135 |
136 | private func setPasteboard(string: String) {
137 | UIPasteboard.general.string = string
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/SettingsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsViewController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import SafariServices
10 | import UIKit
11 |
12 | import ReactorKit
13 | import ReusableKit
14 | import RxCocoa
15 | import RxDataSources
16 | import RxSwift
17 | import AcknowList
18 |
19 | final class SettingViewController: BaseViewController, View {
20 | // MARK: Properties
21 |
22 | private struct Metric {
23 | static let tableViewCellHeight: CGFloat = 44.0
24 | static let sectionFooterHeight: CGFloat = 30.0
25 | static let sectionThanksFooterHeight: CGFloat = 60.0
26 | }
27 |
28 | private struct Font {}
29 |
30 | private struct Reusable {
31 | static let settingCell = ReusableCell()
32 | }
33 |
34 | private struct Localized {
35 | static let setting = NSLocalizedString("setting_title", comment: "Settings")
36 | }
37 |
38 | private var dataSource: RxTableViewSectionedReloadDataSource!
39 |
40 | // MARK: UI Views
41 |
42 | private let tableView = UITableView(frame: .zero, style: .grouped).then {
43 | $0.rowHeight = Metric.tableViewCellHeight
44 | $0.register(Reusable.settingCell)
45 | $0.separatorStyle = .singleLine
46 | }
47 |
48 | // MARK: Initializing
49 |
50 | init(reactor: SettingViewReactor) {
51 | defer { self.reactor = reactor }
52 | super.init()
53 | dataSource = dataSourceFactory()
54 | }
55 |
56 | required init?(coder _: NSCoder) {
57 | fatalError("init(coder:) has not been implemented")
58 | }
59 |
60 | // MARK: View Life Cycle
61 |
62 | override func viewDidLoad() {
63 | super.viewDidLoad()
64 | }
65 |
66 | override func addViews() {
67 | super.addViews()
68 | view.addSubview(tableView)
69 | }
70 |
71 | override func setupConstraints() {
72 | super.setupConstraints()
73 |
74 | tableView.snp.makeConstraints { make in
75 | make.edges.equalToSuperview()
76 | }
77 | }
78 |
79 | // MARK: Binding
80 |
81 | func bind(reactor: SettingViewReactor) {
82 | // Action
83 | rx.viewDidLoad
84 | .map { Localized.setting }
85 | .bind(to: rx.title)
86 | .disposed(by: disposeBag)
87 |
88 | // State
89 | reactor.state.map { $0.sections }
90 | .bind(to: tableView.rx.items(dataSource: dataSource!))
91 | .disposed(by: disposeBag)
92 |
93 | tableView.rx.itemSelected
94 | .subscribe(onNext: { [weak tableView] indexPath in
95 | tableView?.deselectRow(at: indexPath, animated: true)
96 | }).disposed(by: disposeBag)
97 |
98 | tableView.rx.setDelegate(self)
99 | .disposed(by: disposeBag)
100 |
101 | tableView.rx.itemSelected(dataSource: dataSource!)
102 | .subscribe(onNext: { [weak self] sectionItem in
103 | guard let self = self else { return }
104 | switch sectionItem {
105 | case .openSource:
106 | let viewController = AcknowListViewController()
107 | self.navigationController?.pushViewController(viewController, animated: true)
108 |
109 | case .githubRepo:
110 | self.pushToWebVC(urlString: Constants.ETC.repoURL)
111 | }
112 | }).disposed(by: disposeBag)
113 | }
114 |
115 | private func dataSourceFactory() -> RxTableViewSectionedReloadDataSource {
116 | return .init(configureCell: { (_, tableView, indexPath, sectionItem) -> UITableViewCell in
117 | switch sectionItem {
118 | case let .openSource(cellReactor):
119 | let cell = tableView.dequeue(Reusable.settingCell, for: indexPath)
120 | cell.reactor = cellReactor
121 | return cell
122 | case let .githubRepo(cellReactor):
123 | let cell = tableView.dequeue(Reusable.settingCell, for: indexPath)
124 | cell.reactor = cellReactor
125 | return cell
126 | }
127 | })
128 | }
129 |
130 | private func donate() {
131 | guard let firstLanguage = Locale.preferredLanguages.first else { return }
132 |
133 |
134 | let urlString = firstLanguage.hasPrefix("ko") ? WebLinks.kakaoChat : WebLinks.SurveyFormGoogle
135 | pushToWebVC(urlString: urlString)
136 | }
137 |
138 | // MARK: Route
139 |
140 | private func pushToWebVC(urlString: String) {
141 | guard let url = URL(string: urlString) else { return }
142 | let controller = SFSafariViewController(url: url)
143 | present(controller, animated: true, completion: nil)
144 | }
145 |
146 | private func openURL(urlString: String) {
147 | guard let url = URL(string: urlString) else { return }
148 | UIApplication.shared.open(url, options: [:], completionHandler: nil)
149 | }
150 | }
151 |
152 | // MARK: - UITableViewDelegate
153 |
154 | extension SettingViewController: UITableViewDelegate {
155 | func tableView(_: UITableView, viewForFooterInSection section: Int) -> UIView? {
156 | guard let type = SettingFooterType(rawValue: section) else { return nil }
157 | let footerReactor = SettingSectionFooterViewReactor(type: type)
158 | return SettingSectionFooterView(reactor: footerReactor)
159 | }
160 |
161 | func tableView(_: UITableView, heightForFooterInSection section: Int) -> CGFloat {
162 | guard let type = SettingFooterType(rawValue: section) else { return 0.0 }
163 | switch type {
164 | case .dataComment:
165 | return Metric.sectionFooterHeight
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/SettingsViewReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsViewReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import ReactorKit
10 | import RxCocoa
11 | import RxSwift
12 |
13 | final class SettingViewReactor: Reactor {
14 | typealias Action = NoAction
15 |
16 | struct State {
17 |
18 | var usageSectionItems: [SettingSectionItem] {
19 | return [
20 | .openSource(SettingCellReactor(type: .openSource)),
21 | .githubRepo(SettingCellReactor(type: .githubRepo))
22 | ]
23 | }
24 | var sections: [SettingSection] {
25 | return [.usage(self.usageSectionItems)]
26 | }
27 | }
28 |
29 | let initialState: State
30 |
31 | // MARK: Initializing
32 |
33 | init() {
34 | initialState = State()
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/WriteViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WriteViewController.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ReactorKit
11 | import RxCocoa
12 | import RxSwift
13 |
14 | final class WriteViewController: BaseViewController, View {
15 |
16 | // MARK: Properties
17 |
18 | private struct Metric {
19 | static let textViewTop: CGFloat = 15.0
20 | static let textSize: CGFloat = 15.0
21 | }
22 |
23 | private struct Font {
24 | static let textViewStyle = UIFont.systemFont(ofSize: Metric.textSize,
25 | weight: .regular)
26 | }
27 |
28 | private struct Localized {
29 | static let writeTitle = NSLocalizedString("write_title", comment: "추가하기")
30 | static let editTitle = NSLocalizedString("edit_title", comment: "편집하기")
31 | static let close = NSLocalizedString("common_close", comment: "닫기")
32 | static let save = NSLocalizedString("common_save", comment: "저장")
33 | }
34 |
35 | // MARK: Initializing
36 |
37 | private let leftBarButtonItem = UIBarButtonItem(title: Localized.close,
38 | style: .plain,
39 | target: nil,
40 | action: nil)
41 |
42 | private let rightBarButtonItem = UIBarButtonItem(title: Localized.save,
43 | style: .plain,
44 | target: nil,
45 | action: nil)
46 |
47 | private let textView = UITextView().then {
48 | $0.backgroundColor = Color.background
49 | $0.textColor = Color.title
50 | $0.font = Font.textViewStyle
51 | }
52 |
53 | init(reactor: WriteViewReactor) {
54 | super.init()
55 | self.reactor = reactor
56 | }
57 |
58 | required init?(coder _: NSCoder) {
59 | fatalError("init(coder:) has not been implemented")
60 | }
61 |
62 | // MARK: View Life Cycle
63 |
64 | override func viewDidLoad() {
65 | super.viewDidLoad()
66 | }
67 |
68 | override func addViews() {
69 | super.addViews()
70 |
71 | self.view.backgroundColor = Color.background
72 | navigationItem.leftBarButtonItem = leftBarButtonItem
73 | navigationItem.rightBarButtonItem = rightBarButtonItem
74 | view.addSubview(textView)
75 | }
76 |
77 | override func setupConstraints() {
78 | super.setupConstraints()
79 |
80 | textView.snp.makeConstraints { make in
81 | make.top.equalTo(Metric.textViewTop)
82 | make.left.right.equalToSuperview()
83 | make.height.equalToSuperview()
84 | }
85 | }
86 |
87 | // MARK: Binding
88 |
89 | func bind(reactor: WriteViewReactor) {
90 | // State
91 |
92 | self.rx.viewDidLoad
93 | .asDriver()
94 | .drive(onNext: { [weak self] _ in
95 | guard let self = self else { return }
96 | self.textView.becomeFirstResponder()
97 | })
98 | .disposed(by: self.disposeBag)
99 |
100 | rx.viewWillAppear
101 | .map { _ in Reactor.Action.initializeData }
102 | .bind(to: reactor.action)
103 | .disposed(by: self.disposeBag)
104 |
105 | leftBarButtonItem.rx.tap
106 | .subscribe(onNext: { [weak self] _ in
107 | guard let self = self else { return }
108 | self.dismiss(animated: true, completion: nil)
109 | })
110 | .disposed(by: disposeBag)
111 |
112 | rightBarButtonItem.rx.tap
113 | .subscribe(onNext: { [weak self] _ in
114 | guard let self = self else { return }
115 | let mode = self.reactor?.currentState.mode
116 | switch mode {
117 | case .edit:
118 | logger.verbose("edit")
119 | let text = self.textView.text ?? ""
120 | self.reactor?.action.onNext(.edit(text))
121 | case .write:
122 | logger.verbose("save")
123 | let text = self.textView.text ?? ""
124 | self.reactor?.action.onNext(.save(text))
125 | default:
126 | break
127 | }
128 | })
129 | .disposed(by: disposeBag)
130 | self.textView.rx.text.orEmpty
131 | .subscribe(onNext: { [weak self] string in
132 | guard let self = self else { return }
133 |
134 | if string.isEmpty {
135 | self.rightBarButtonItem.isEnabled = false
136 | } else {
137 | self.rightBarButtonItem.isEnabled = true
138 | }
139 |
140 | logger.debug(string)
141 | }).disposed(by: self.disposeBag)
142 |
143 | reactor.state.map { $0.text }
144 | .distinctUntilChanged()
145 | .bind(to: textView.rx.text)
146 | .disposed(by: disposeBag)
147 |
148 | reactor.state.map { $0.isUpdated }
149 | .filter{ $0 }
150 | .distinctUntilChanged()
151 | .subscribe(onNext: { [weak self] isUpdated in
152 | guard let self = self else { return }
153 | let mode = self.reactor?.currentState.mode
154 | switch mode {
155 | case .edit:
156 | logger.verbose("편집 완료")
157 | self.dismiss(animated: true, completion: nil)
158 | case .write:
159 | logger.verbose("새로 추가 완료")
160 | self.dismiss(animated: true, completion: nil)
161 | default:
162 | break
163 | }
164 | })
165 | .disposed(by: self.disposeBag)
166 |
167 | reactor.state.map { $0.mode }
168 | .distinctUntilChanged()
169 | .subscribe(onNext: { [weak self] mode in
170 | guard let self = self else { return }
171 | switch mode {
172 | case .edit:
173 | self.title = Localized.editTitle
174 | case .write:
175 | self.title = Localized.writeTitle
176 | }
177 | }).disposed(by: self.disposeBag)
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ViewControllers/WriteViewReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WriteViewReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ReactorKit
11 | import RxCocoa
12 | import RxSwift
13 |
14 |
15 | final class WriteViewReactor: Reactor {
16 |
17 | enum ContentMode {
18 | case write
19 | case edit
20 | }
21 |
22 | enum Action {
23 | case initializeData
24 | case getPasteboard
25 | case getIndex
26 | case edit(String)
27 | case save(String)
28 | }
29 |
30 | enum Mutation {
31 | case getIndex
32 | case setText(String)
33 | case edit(String)
34 | case save(String)
35 | }
36 |
37 | struct State {
38 | var text: String?
39 | var isUpdated: Bool = false
40 | var mode: ContentMode
41 | var currentIndex: Int?
42 | }
43 |
44 | let initialState: State
45 | let utility = Utility()
46 |
47 | // MARK: Initializing
48 |
49 | init(mode: ContentMode, text: String?) {
50 | initialState = State(text: text, mode: mode)
51 | }
52 |
53 | // MARK: Mutate
54 |
55 | func mutate(action: Action) -> Observable {
56 | switch action {
57 | case .initializeData:
58 | switch currentState.mode {
59 | case .edit:
60 | return .just(Mutation.getIndex)
61 | case .write:
62 | return .empty()
63 | default:
64 | return .empty()
65 | }
66 | case .getIndex:
67 | return .just(Mutation.getIndex)
68 | case .getPasteboard:
69 | let text = getPasteboard()
70 | return .just(.setText(text))
71 | case let .edit(text):
72 | return .just(.edit(text))
73 | case let .save(text):
74 | return .just(.save(text))
75 |
76 | }
77 | }
78 |
79 | // MARK: Reduce
80 |
81 | func reduce(state: State, mutation: Mutation) -> State {
82 | var state = state
83 | switch mutation {
84 | case .getIndex:
85 | if let text = state.text {
86 | let index = utility.getIndex(text: text)
87 | state.currentIndex = index
88 | }
89 | return state
90 |
91 | case let .setText(string):
92 | state.text = string
93 | return state
94 |
95 | case let .edit(text):
96 | if let index = state.currentIndex {
97 | let isEdited = utility.updateWord(index: index, text: text)
98 | state.isUpdated = isEdited
99 | return state
100 | }
101 |
102 | case let .save(text):
103 | let isSaved = utility.saveWord(text: text)
104 | state.isUpdated = isSaved
105 | return state
106 | }
107 |
108 | return state
109 | }
110 |
111 | func getPasteboard() -> String {
112 | guard let copyText = UIPasteboard.general.string else { return "" }
113 | if copyText.isEmpty == false {
114 | logger.verbose("[+] detected something in clipboard")
115 | return copyText
116 | }
117 |
118 | return ""
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/MainTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainTableViewCell.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import ReactorKit
12 | import RxCocoa
13 | import RxSwift
14 |
15 | final class MainTableViewCell: BaseTableViewCell, View {
16 |
17 | typealias Reactor = MainTableViewCellReactor
18 |
19 | private struct Metric {
20 | static let titleLeft: CGFloat = 10.0
21 | }
22 |
23 | // MARK: Initializing
24 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
25 | super.init(style: style, reuseIdentifier: reuseIdentifier)
26 | self.accessoryType = .disclosureIndicator
27 | self.textLabel?.font = UIFont.systemFont(ofSize: 14.0)
28 | }
29 |
30 | required init?(coder aDecoder: NSCoder) {
31 | fatalError("init(coder:) has not been implemented")
32 | }
33 |
34 | // MARK: Initializing
35 | override func addViews() {
36 | super.addViews()
37 | self.contentView.backgroundColor = Color.background
38 | self.selectionStyle = .none
39 | }
40 |
41 | override func setupConstraints() {
42 | super.setupConstraints()
43 | }
44 |
45 | // MARK: Binding
46 | func bind(reactor: MainTableViewCellReactor) {
47 |
48 | reactor.state.map { $0.list.message }
49 | .distinctUntilChanged()
50 | .bind(to: self.textLabel!.rx.text)
51 | .disposed(by: self.disposeBag)
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/MainTableViewCellReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainTableViewCellReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import ReactorKit
10 | import RxCocoa
11 | import RxSwift
12 |
13 | final class MainTableViewCellReactor: Reactor {
14 | typealias Action = NoAction
15 | typealias Mutaiton = NoMutation
16 |
17 | struct State {
18 | var list: MainViewReactor.Item
19 | }
20 |
21 | let initialState: State
22 |
23 | init(list: MainViewReactor.Item) {
24 | initialState = State(list: list)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/SettingCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingCell.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import ReactorKit
12 | import RxCocoa
13 | import RxSwift
14 |
15 | final class SettingCell: BaseTableViewCell, ReactorKit.View {
16 |
17 | typealias Reactor = SettingCellReactor
18 |
19 | // MARK: Properties
20 |
21 | // MARK: Initializing
22 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
23 | super.init(style: style, reuseIdentifier: reuseIdentifier)
24 | self.accessoryType = .disclosureIndicator
25 | self.textLabel?.font = UIFont.systemFont(ofSize: 14.0)
26 | }
27 |
28 | required init?(coder aDecoder: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 |
32 | override func addViews() {
33 | super.addViews()
34 | // self.contentView.backgroundColor = .white
35 | }
36 |
37 | override func setupConstraints() {
38 | super.setupConstraints()
39 | }
40 |
41 | // MARK: Binding
42 | func bind(reactor: Reactor) {
43 |
44 | reactor.state.map { $0.type.title }
45 | .bind(to: self.textLabel!.rx.text)
46 | .disposed(by: self.disposeBag)
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/SettingCellReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingCellReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import ReactorKit
10 | import RxCocoa
11 | import RxSwift
12 |
13 | final class SettingCellReactor: Reactor {
14 | typealias Action = NoAction
15 |
16 | struct State {
17 | var type: SettingMenuTypes
18 | }
19 |
20 | let initialState: State
21 |
22 | init(type: SettingMenuTypes) {
23 | initialState = State(type: type)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/SettingSectionFooterView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSectionFooterView.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import ReactorKit
12 | import RxCocoa
13 | import RxSwift
14 |
15 | final class SettingSectionFooterView: UIView, ReactorKit.View {
16 |
17 | typealias Reactor = SettingSectionFooterViewReactor
18 |
19 | // MARK: Properties
20 | private struct Metric {
21 | static let descriptionLeading: CGFloat = 10.0
22 | static let descriptionTrailing: CGFloat = -10.0
23 | }
24 |
25 | private struct Font {
26 | static let description = UIFont.systemFont(ofSize: 12.0, weight: .regular)
27 | }
28 |
29 | var disposeBag = DisposeBag()
30 |
31 | // MARK: UI Views
32 | private let descriptionLabel = UILabel().then {
33 | $0.font = Font.description
34 | $0.textColor = Color.description
35 | $0.text = ""
36 | $0.textAlignment = .left
37 | }
38 |
39 | // MARK: Initializing
40 | init(reactor: Reactor) {
41 | defer { self.reactor = reactor }
42 | super.init(frame: .zero)
43 | addViews()
44 | setupConstraints()
45 | }
46 |
47 | required init?(coder: NSCoder) {
48 | fatalError("init(coder:) has not been implemented")
49 | }
50 |
51 | private func addViews() {
52 | self.addSubview(descriptionLabel)
53 | }
54 |
55 | private func setupConstraints() {
56 | descriptionLabel.snp.makeConstraints { make in
57 | make.leading.equalTo(Metric.descriptionLeading)
58 | make.trailing.equalTo(Metric.descriptionTrailing)
59 | make.top.bottom.equalToSuperview()
60 | }
61 | }
62 |
63 | // MARK: Binding
64 |
65 | func bind(reactor: Reactor) {
66 | reactor.state.map { $0.type.description }
67 | .bind(to: descriptionLabel.rx.text)
68 | .disposed(by: self.disposeBag)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/Views/Cells/SettingSectionFooterViewReactor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingSectionFooterViewReactor.swift
3 | // reactorkitKeyboardExample
4 | //
5 | // Created by Fernando on 2020/04/21.
6 | // Copyright © 2020 tmsae. All rights reserved.
7 | //
8 |
9 |
10 | import ReactorKit
11 | import RxCocoa
12 | import RxSwift
13 |
14 | class SettingSectionFooterViewReactor: Reactor {
15 |
16 | typealias Action = NoAction
17 |
18 | struct State {
19 | var type: SettingFooterType
20 | }
21 |
22 | let initialState: State
23 |
24 | init(type: SettingFooterType) {
25 | initialState = State(type: type)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ko.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/ko.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/reactorkitKeyboardExample/reactorkitKeyboardExample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 | group.com.tmsae.keyboardExample
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------