diff --git a/Empty Swift File.xctemplate/TemplateIcon.png b/Empty Swift File.xctemplate/TemplateIcon.png
new file mode 100644
index 0000000..b349faa
Binary files /dev/null and b/Empty Swift File.xctemplate/TemplateIcon.png differ
diff --git a/Empty Swift File.xctemplate/TemplateIcon@2x.png b/Empty Swift File.xctemplate/TemplateIcon@2x.png
new file mode 100644
index 0000000..fd94e8a
Binary files /dev/null and b/Empty Swift File.xctemplate/TemplateIcon@2x.png differ
diff --git a/Empty Swift File.xctemplate/TemplateInfo.plist b/Empty Swift File.xctemplate/TemplateInfo.plist
new file mode 100644
index 0000000..b5d0c08
--- /dev/null
+++ b/Empty Swift File.xctemplate/TemplateInfo.plist
@@ -0,0 +1,43 @@
+
+
+
+
+ Kind
+ Xcode.IDEFoundation.TextSubstitutionFileTemplateKind
+ Description
+ Empty Swift file template
+ SortOrder
+ 30
+ AllowedTypes
+
+ public.swift-source
+
+ DefaultCompletionName
+ NewScreen
+ MainTemplateFile
+ ___FILEBASENAME___
+ Options
+
+
+ Default
+
+ Identifier
+ fileName
+ Name
+ File name
+ Required
+ YES
+ Type
+ text
+
+
+ Default
+ ___VARIABLE_fileName___
+ Identifier
+ productName
+ Type
+ static
+
+
+
+
diff --git a/Empty Swift File.xctemplate/___FILEBASENAMEASIDENTIFIER___.swift b/Empty Swift File.xctemplate/___FILEBASENAMEASIDENTIFIER___.swift
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Empty Swift File.xctemplate/___FILEBASENAMEASIDENTIFIER___.swift
@@ -0,0 +1 @@
+
diff --git a/HandsApp Network iOS App.xctemplate/AppDefaults.swift b/HandsApp Network iOS App.xctemplate/AppDefaults.swift
new file mode 100644
index 0000000..4c877e8
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/AppDefaults.swift
@@ -0,0 +1,5 @@
+enum AppDefaults {
+ #warning("Replace by your server URL")
+ static let serverBaseUrl = "https://handsapp.ru"
+ static let serverApiBaseUrl = serverBaseUrl + "/api/"
+}
diff --git a/HandsApp Network iOS App.xctemplate/AuthPlugin.swift b/HandsApp Network iOS App.xctemplate/AuthPlugin.swift
new file mode 100644
index 0000000..a63a7bd
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/AuthPlugin.swift
@@ -0,0 +1,17 @@
+import Moya
+
+// MARK: - AuthPlugin
+
+class AuthPlugin: PluginType {
+ private let keychain = Keychain()
+
+ func prepare(_ request: URLRequest, target _: TargetType) -> URLRequest {
+ let jwtToken: String = keychain.get(KeychainKeys.jwtToken) ?? ""
+ var request = request
+ request.addValue(
+ "JWT \(jwtToken)",
+ forHTTPHeaderField: "Authorization"
+ )
+ return request
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/ErrorHandler.swift b/HandsApp Network iOS App.xctemplate/ErrorHandler.swift
new file mode 100644
index 0000000..033008e
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/ErrorHandler.swift
@@ -0,0 +1,10 @@
+import Foundation
+
+class ErrorHandler {
+ var messagesView: UserMessagesView?
+
+ func handle(error: Error) {
+ let message = error.localizedDescription
+ messagesView?.showErrorAlert(withMessage: message)
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/ErrorHandlingPlugin.swift b/HandsApp Network iOS App.xctemplate/ErrorHandlingPlugin.swift
new file mode 100644
index 0000000..b15b086
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/ErrorHandlingPlugin.swift
@@ -0,0 +1,26 @@
+import Moya
+import Result
+
+class ErrorHandlingPlugin: PluginType {
+ private let reachabilityManager = ReachabilityManager(host: AppDefaults.serverApiBaseUrl)
+ weak var errorHandler: ErrorHandler?
+
+ func didReceive(_ result: Result, target _: TargetType) {
+ guard case let .failure(moyaError) = result,
+ let errorHandler = errorHandler else { return }
+
+ if case let .underlying(error, _) = moyaError,
+ (error as NSError).code == NSURLErrorCancelled {
+ return
+ }
+
+ var error: Error = moyaError
+ if let reachabilityManager = reachabilityManager,
+ !reachabilityManager.isReachable {
+ error = NetworkReachabilityError()
+ } else if let statusCode = moyaError.response?.statusCode {
+ error = HTTPNetworkError(statusCode: statusCode)
+ }
+ errorHandler.handle(error: error)
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/HTTPNetworkError.swift b/HandsApp Network iOS App.xctemplate/HTTPNetworkError.swift
new file mode 100644
index 0000000..cd90c5d
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/HTTPNetworkError.swift
@@ -0,0 +1,26 @@
+import Foundation
+
+struct HTTPNetworkError: Error {
+ let statusCode: Int
+}
+
+extension HTTPNetworkError: LocalizedError {
+ var errorDescription: String? {
+ return localizedDescription
+ }
+
+ var localizedDescription: String {
+ switch statusCode {
+ case 401:
+ return R.string.localizable.network_error_no_registration()
+ case 403:
+ return R.string.localizable.network_error_forbidden()
+ case 404:
+ return R.string.localizable.network_error_not_found()
+ case 500, 502:
+ return R.string.localizable.network_error_internal_server_error()
+ default:
+ return R.string.localizable.network_error_default()
+ }
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/Keychain.swift b/HandsApp Network iOS App.xctemplate/Keychain.swift
new file mode 100644
index 0000000..8e88c52
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/Keychain.swift
@@ -0,0 +1,8 @@
+import KeychainSwift
+
+class Keychain: KeychainSwift {
+ override init() {
+ let prefix = Bundle.main.bundleIdentifier ?? "ru.handsapp" + "_keychain_"
+ super.init(keyPrefix: prefix)
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/KeychainKeys.swift b/HandsApp Network iOS App.xctemplate/KeychainKeys.swift
new file mode 100644
index 0000000..cdbf715
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/KeychainKeys.swift
@@ -0,0 +1,3 @@
+enum KeychainKeys {
+ static let jwtToken = "jwtToken"
+}
diff --git a/HandsApp Network iOS App.xctemplate/Localizable.strings b/HandsApp Network iOS App.xctemplate/Localizable.strings
new file mode 100644
index 0000000..3e50014
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/Localizable.strings
@@ -0,0 +1,12 @@
+"error_text" = "Ошибка";
+"ok" = "Ок";
+
+// MARK: - Errors
+"network_error_forbidden" = "Извините, у вас недостаточно прав для выполнения данной операции ⛔";
+"network_error_not_found" = "Ресурс не найден 🤷";
+"network_error_internal_server_error" = "Внутренняя ошибка сервера. Попробуйте повторить запрос через несколько минут 💤";
+"network_error_default" = "Упс! Что-то пошло не так";
+"network_error_no_registration" = "Ошибка авторизации";
+"check_connection_and_try_again" = "Нет соединения с интернетом";
+"user_is_blocked" = "Пользователь заблокирован";
+"contact_support" = "Обратитесь в поддержку";
diff --git a/HandsApp Network iOS App.xctemplate/NetworkReachabilityError.swift b/HandsApp Network iOS App.xctemplate/NetworkReachabilityError.swift
new file mode 100644
index 0000000..04807ac
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/NetworkReachabilityError.swift
@@ -0,0 +1,11 @@
+import Foundation
+
+struct NetworkReachabilityError: Error, LocalizedError {
+ var errorDescription: String? {
+ return localizedDescription
+ }
+
+ var localizedDescription: String {
+ return String()
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/Podfile b/HandsApp Network iOS App.xctemplate/Podfile
new file mode 100644
index 0000000..15c6d85
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/Podfile
@@ -0,0 +1,28 @@
+use_frameworks!
+inhibit_all_warnings!
+
+platform :ios, '11.0'
+
+def appcenter
+ pod 'AppCenter'
+ pod 'AppCenter/Distribute'
+ pod 'AppCenter/Crashes'
+end
+
+target '___PACKAGENAME___' do
+ # Code Tools
+ pod 'R.swift'
+ pod 'SwiftFormat/CLI'
+ pod 'SwiftLint'
+
+ # SDKs
+ appcenter
+
+ # UI
+ pod 'HandsAppUI'
+
+ # Networking
+ pod 'SDWebImage'
+ pod 'Moya'
+ pod 'KeychainSwift'
+end
diff --git a/HandsApp Network iOS App.xctemplate/ReachabilityManager.swift b/HandsApp Network iOS App.xctemplate/ReachabilityManager.swift
new file mode 100644
index 0000000..1851720
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/ReachabilityManager.swift
@@ -0,0 +1,3 @@
+import Alamofire
+
+class ReachabilityManager: NetworkReachabilityManager {}
diff --git a/HandsApp Network iOS App.xctemplate/ServerApi.swift b/HandsApp Network iOS App.xctemplate/ServerApi.swift
new file mode 100644
index 0000000..cd35ac5
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/ServerApi.swift
@@ -0,0 +1,51 @@
+import Moya
+
+enum ServerApi {
+ #warning("This is sample implementation of api endpoint. Remove it if needed")
+ case auth(firToken: String)
+}
+
+// MARK: - Moya setup
+
+extension ServerApi: TargetType {
+ var baseURL: URL {
+ guard let url = URL(string: AppDefaults.serverApiBaseUrl) else {
+ fatalError("Failed to provide server api base url")
+ }
+ return url
+ }
+
+ var path: String {
+ switch self {
+ case .auth:
+ return "auth/firebase"
+ }
+ }
+
+ var method: Method {
+ switch self {
+ case .auth:
+ return .post
+ }
+ }
+
+ var sampleData: Data {
+ return Data()
+ }
+
+ var validationType: ValidationType {
+ return .successCodes
+ }
+
+ var task: Task {
+ switch self {
+ case let .auth(firToken):
+ let parameters = ["access_token": firToken]
+ return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
+ }
+ }
+
+ var headers: [String: String]? {
+ return nil
+ }
+}
diff --git a/HandsApp Network iOS App.xctemplate/TemplateInfo.plist b/HandsApp Network iOS App.xctemplate/TemplateInfo.plist
new file mode 100644
index 0000000..ebf0a14
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/TemplateInfo.plist
@@ -0,0 +1,209 @@
+
+
+
+
+ Kind
+ Xcode.Xcode3.ProjectTemplateUnitKind
+ Identifier
+ ru.handsapp.dt.unit.MvpNetworkApplication
+ Ancestors
+
+ ru.handsapp.dt.unit.MVPApplication
+
+ Concrete
+
+ Description
+ This template is for network MVP application.
+ SortOrder
+ 1
+ Nodes
+
+ ../Podfile
+ Resources/Strings/Localizable.strings
+ Resources/Constants/AppDefaults.swift
+ Resources/Constants/KeychainKeys.swift
+ Library/Error Handling/ErrorHandler.swift
+ Library/Protocols/UserMessagesView.swift
+ Services/Keychain.swift
+ Services/Network/Api/ServerApi.swift
+ Services/Network/Plugins/AuthPlugin.swift
+ Services/Network/Plugins/ErrorHandlingPlugin.swift
+ Services/Network/Errors/HTTPNetworkError.swift
+ Services/Network/Errors/NetworkReachabilityError.swift
+ Services/Network/ReachabilityManager.swift
+ Models/Network/Responses/.gitkeep
+ Models/Network/Requests/.gitkeep
+ Models/Mapping/.gitkeep
+
+ Definitions
+
+ ../Podfile
+
+ Path
+ Podfile
+ Group
+ Non-iOS Resources
+
+ Resources/Strings/Localizable.strings
+
+ Path
+ Localizable.strings
+ Group
+
+ Resources
+ Strings
+
+
+ Resources/Constants/AppDefaults.swift
+
+ Group
+
+ Resources
+ Constants
+
+ Path
+ AppDefaults.swift
+
+ Resources/Constants/KeychainKeys.swift
+
+ Group
+
+ Resources
+ Constants
+
+ Path
+ KeychainKeys.swift
+
+ Library/Error Handling/ErrorHandler.swift
+
+ Group
+
+ Library
+ Error Handling
+
+ Path
+ ErrorHandler.swift
+
+ Library/Protocols/UserMessagesView.swift
+
+ Group
+
+ Library
+ Protocols
+
+ Path
+ UserMessagesView.swift
+
+ Services/Keychain.swift
+
+ Group
+ Services
+ Path
+ Keychain.swift
+
+ Services/Network/Api/ServerApi.swift
+
+ Group
+
+ Services
+ Network
+ Api
+
+ Path
+ ServerApi.swift
+
+ Services/Network/Plugins/AuthPlugin.swift
+
+ Group
+
+ Services
+ Network
+ Plugins
+
+ Path
+ AuthPlugin.swift
+
+ Services/Network/Plugins/ErrorHandlingPlugin.swift
+
+ Group
+
+ Services
+ Network
+ Plugins
+
+ Path
+ ErrorHandlingPlugin.swift
+
+ Services/Network/Errors/HTTPNetworkError.swift
+
+ Group
+
+ Services
+ Network
+ Errors
+
+ Path
+ HTTPNetworkError.swift
+
+ Services/Network/Errors/NetworkReachabilityError.swift
+
+ Group
+
+ Services
+ Network
+ Errors
+
+ Path
+ NetworkReachabilityError.swift
+
+ Services/Network/ReachabilityManager.swift
+
+ Group
+
+ Services
+ Network
+
+ Path
+ ReachabilityManager.swift
+
+ Models/Network/Requests/.gitkeep
+
+ Group
+
+ Models
+ Network
+ Requests
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Models/Network/Responses/.gitkeep
+
+ Group
+
+ Models
+ Network
+ Responses
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Models/Mapping/.gitkeep
+
+ Group
+
+ Models
+ Mapping
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+
+
+
diff --git a/HandsApp Network iOS App.xctemplate/UserMessagesView.swift b/HandsApp Network iOS App.xctemplate/UserMessagesView.swift
new file mode 100644
index 0000000..42741a5
--- /dev/null
+++ b/HandsApp Network iOS App.xctemplate/UserMessagesView.swift
@@ -0,0 +1,19 @@
+import UIKit
+
+protocol UserMessagesView {
+ func showAlert(withTitle title: String?, message: String?)
+ func showErrorAlert(withMessage message: String)
+}
+
+extension UserMessagesView where Self: UIViewController {
+ func showAlert(withTitle title: String?, message: String?) {
+ let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
+ let okAction = UIAlertAction(title: R.string.localizable.ok(), style: .default, handler: nil)
+ alertController.addAction(okAction)
+ present(alertController, animated: true)
+ }
+
+ func showErrorAlert(withMessage message: String) {
+ showAlert(withTitle: R.string.localizable.error_text(), message: message)
+ }
+}
diff --git a/Single View App With Code Tools.xctemplate/.gitignore b/HandsApp iOS App.xctemplate/.gitignore
similarity index 97%
rename from Single View App With Code Tools.xctemplate/.gitignore
rename to HandsApp iOS App.xctemplate/.gitignore
index 770e547..79fe851 100644
--- a/Single View App With Code Tools.xctemplate/.gitignore
+++ b/HandsApp iOS App.xctemplate/.gitignore
@@ -18,6 +18,9 @@ Carthage/Build
# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
Pods/
+### Fastlane Screenshots ###
+screenshots/
+
### macOS ###
# General
.DS_Store
diff --git a/HandsApp iOS App.xctemplate/.swiftformat b/HandsApp iOS App.xctemplate/.swiftformat
new file mode 100644
index 0000000..1e8986e
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/.swiftformat
@@ -0,0 +1,2 @@
+# rules
+--disable trailingCommas
\ No newline at end of file
diff --git a/Single View App With Code Tools.xctemplate/.swiftlint.yml b/HandsApp iOS App.xctemplate/.swiftlint.yml
similarity index 88%
rename from Single View App With Code Tools.xctemplate/.swiftlint.yml
rename to HandsApp iOS App.xctemplate/.swiftlint.yml
index ef653d4..e7887dc 100644
--- a/Single View App With Code Tools.xctemplate/.swiftlint.yml
+++ b/HandsApp iOS App.xctemplate/.swiftlint.yml
@@ -28,7 +28,7 @@ opt_in_rules:
warning_threshold: 1
line_length:
- warning: 100
+ warning: 120
ignores_function_declarations: true
ignores_comments: true
ignores_interpolated_strings: true
@@ -36,11 +36,11 @@ line_length:
type_body_length:
- 250 # warning
- - 300 # error (должно быть 300)
+ - 300 # error
file_length:
warning: 300 # warning
- error: 400 # error (должно быть 400)
+ error: 400 # error
identifier_name:
min_length:
@@ -57,5 +57,5 @@ excluded:
- Carthage
- Pods
- Documents
- - R.generated.swift
-
\ No newline at end of file
+ - "*.generated.swift"
+ - "*/SnapshotHelper.swift"
diff --git a/HandsApp iOS App.xctemplate/ApiKeys.swift b/HandsApp iOS App.xctemplate/ApiKeys.swift
new file mode 100755
index 0000000..adb9146
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/ApiKeys.swift
@@ -0,0 +1,4 @@
+enum ApiKeys {
+ #warning("Replace with real key via global search (Cmd + Shift + F)")
+ static let appCenter = "APP_CENTER_API_KEY"
+}
diff --git a/HandsApp iOS App.xctemplate/AppDelegate.swift b/HandsApp iOS App.xctemplate/AppDelegate.swift
new file mode 100755
index 0000000..a8f6a39
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/AppDelegate.swift
@@ -0,0 +1,31 @@
+import AppCenter
+import AppCenterAnalytics
+import AppCenterCrashes
+import AppCenterDistribute
+import HandsAppUI
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate, HandsAppDelegate {
+ var window: UIWindow?
+
+ var theme: Theme.Type {
+ return DefaultTheme.self
+ }
+
+ func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ startAppCenter()
+ setupWindow()
+ return true
+ }
+
+ private func startAppCenter() {
+ let services: [AnyClass] = [MSAnalytics.self, MSDistribute.self, MSCrashes.self]
+ MSAppCenter.start(ApiKeys.appCenter, withServices: services)
+ }
+
+ private func setupWindow() {
+ window = UIWindow(frame: UIScreen.main.bounds)
+ window?.makeKeyAndVisible()
+ }
+}
diff --git a/HandsApp iOS App.xctemplate/Assets.xcassets/.gitkeep b/HandsApp iOS App.xctemplate/Assets.xcassets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/HandsApp iOS App.xctemplate/Gemfile b/HandsApp iOS App.xctemplate/Gemfile
new file mode 100755
index 0000000..8ae4009
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/Gemfile
@@ -0,0 +1,11 @@
+source "https://rubygems.org"
+
+# Ensure github repositories are fetched using HTTPS
+git_source(:github) do |repo_name|
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
+ puts(repo_name)
+ "https://github.com/#{repo_name}.git"
+end if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('2')
+
+gem 'cocoapods'
+gem 'generamba'
diff --git a/HandsApp iOS App.xctemplate/Info.plist b/HandsApp iOS App.xctemplate/Info.plist
new file mode 100644
index 0000000..b0e3d57
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/Info.plist
@@ -0,0 +1,43 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ appcenter-APP_CENTER_API_KEY
+
+
+
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+
+
diff --git a/Single View App With Code Tools.xctemplate/Main.storyboard b/HandsApp iOS App.xctemplate/LaunchScreen.storyboard
similarity index 69%
rename from Single View App With Code Tools.xctemplate/Main.storyboard
rename to HandsApp iOS App.xctemplate/LaunchScreen.storyboard
index 587b971..bfa3612 100644
--- a/Single View App With Code Tools.xctemplate/Main.storyboard
+++ b/HandsApp iOS App.xctemplate/LaunchScreen.storyboard
@@ -1,5 +1,5 @@
-
-
+
+
@@ -7,18 +7,19 @@
-
+
-
-
+
+
-
+
+
diff --git a/HandsApp iOS App.xctemplate/Localizable.strings b/HandsApp iOS App.xctemplate/Localizable.strings
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/Localizable.strings
@@ -0,0 +1 @@
+
diff --git a/HandsApp iOS App.xctemplate/Podfile b/HandsApp iOS App.xctemplate/Podfile
new file mode 100644
index 0000000..57e08d1
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/Podfile
@@ -0,0 +1,23 @@
+use_frameworks!
+inhibit_all_warnings!
+
+platform :ios, '11.0'
+
+def appcenter
+ pod 'AppCenter'
+ pod 'AppCenter/Distribute'
+ pod 'AppCenter/Crashes'
+end
+
+target '___PACKAGENAME___' do
+ # Code Tools
+ pod 'R.swift'
+ pod 'SwiftFormat/CLI'
+ pod 'SwiftLint'
+
+ # SDKs
+ appcenter
+
+ # UI
+ pod 'HandsAppUI'
+end
\ No newline at end of file
diff --git a/HandsApp iOS App.xctemplate/Rambafile b/HandsApp iOS App.xctemplate/Rambafile
new file mode 100755
index 0000000..3adc75a
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/Rambafile
@@ -0,0 +1,37 @@
+### Headers settings
+company: ___ORGANIZATIONNAME___
+
+### Xcode project settings
+project_name: ___PACKAGENAME___
+xcodeproj_path: ___PACKAGENAME___.xcodeproj
+
+### Code generation settings section
+# The main project target name
+project_target: ___PACKAGENAME___
+
+# The file path for new screens
+project_file_path: ___PACKAGENAME___/Screens
+
+# The Xcode group path to new screens
+project_group_path: ___PACKAGENAME___/Screens
+
+### Tests generation settings section
+# The tests target name
+test_target: ___PACKAGENAME___Tests
+
+# The file path for new tests
+test_file_path: ___PACKAGENAME___Tests/Screens
+
+# The Xcode group path to new tests
+test_group_path: ___PACKAGENAME___Tests/Screens
+
+### Dependencies settings section
+podfile_path: Podfile
+
+### Catalogs
+catalogs:
+- 'https://github.com/HandsAppTeam/generamba-templates'
+
+### Templates
+templates:
+- {name: handsapp_mvp_screen}
\ No newline at end of file
diff --git a/HandsApp iOS App.xctemplate/ScreenTransitionable.swift b/HandsApp iOS App.xctemplate/ScreenTransitionable.swift
new file mode 100644
index 0000000..f295bea
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/ScreenTransitionable.swift
@@ -0,0 +1,38 @@
+//
+// ScreenTransitionable.swift
+//
+// Created by Никита Красавин on 10/09/2019.
+// Copyright © 2019 Handsapp. All rights reserved.
+//
+
+import UIKit
+
+protocol ScreenTransitionable: AnyObject {
+ func showScreen(_ screen: UIViewController)
+ func dismissView(animated: Bool, completion: (() -> Void)?)
+ func presentScreen(_ screen: UIViewController, animated: Bool, completion: (() -> Void)?)
+ func pop(animated: Bool)
+ func push(screen: UIViewController, animated: Bool)
+}
+
+extension ScreenTransitionable where Self: UIViewController {
+ func showScreen(_ screen: UIViewController) {
+ show(screen, sender: nil)
+ }
+
+ func dismissView(animated: Bool, completion: (() -> Void)?) {
+ presentingViewController?.dismiss(animated: animated, completion: completion)
+ }
+
+ func presentScreen(_ screen: UIViewController, animated: Bool, completion: (() -> Void)?) {
+ present(screen, animated: animated, completion: completion)
+ }
+
+ func pop(animated: Bool) {
+ navigationController?.popViewController(animated: animated)
+ }
+
+ func push(screen: UIViewController, animated: Bool) {
+ navigationController?.pushViewController(screen, animated: animated)
+ }
+}
diff --git a/HandsApp iOS App.xctemplate/TemplateIcon.png b/HandsApp iOS App.xctemplate/TemplateIcon.png
new file mode 100644
index 0000000..b349faa
Binary files /dev/null and b/HandsApp iOS App.xctemplate/TemplateIcon.png differ
diff --git a/HandsApp iOS App.xctemplate/TemplateIcon@2x.png b/HandsApp iOS App.xctemplate/TemplateIcon@2x.png
new file mode 100644
index 0000000..fd94e8a
Binary files /dev/null and b/HandsApp iOS App.xctemplate/TemplateIcon@2x.png differ
diff --git a/HandsApp iOS App.xctemplate/TemplateInfo.plist b/HandsApp iOS App.xctemplate/TemplateInfo.plist
new file mode 100644
index 0000000..c84bbc4
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/TemplateInfo.plist
@@ -0,0 +1,470 @@
+
+
+
+
+ Kind
+ Xcode.Xcode3.ProjectTemplateUnitKind
+ Identifier
+ ru.handsapp.dt.unit.MVPApplication
+ Ancestors
+
+ com.apple.dt.unit.applicationBase
+ com.apple.dt.unit.iosBase
+ com.apple.dt.unit.languageChoice
+
+ Concrete
+
+ Description
+ This template is for MVP application.
+ SortOrder
+ 1
+ Options
+
+
+ Identifier
+ hasUnitTests
+ Name
+ Include Unit Tests
+ NotPersisted
+
+ SortOrder
+ 100
+ Type
+ checkbox
+ Default
+ true
+ Units
+
+ true
+
+ Components
+
+
+ Identifier
+ com.apple.dt.unit.cocoaTouchApplicationUnitTestBundle
+ Name
+ ___PACKAGENAME___Tests
+
+
+
+
+
+
+ Identifier
+ languageChoice
+ Units
+
+ Objective-C
+
+ Nodes
+
+ main.m:comments
+ main.m:imports:importCocoa
+ main.m:imports:importHeader:AppDelegate.h
+ main.m:main:UIApplicationMain
+ AppDelegate.h:comments
+ AppDelegate.h:imports:importCocoa
+ AppDelegate.h:interface(AppDelegate : UIResponder <UIApplicationDelegate>)
+ AppDelegate.h:interface:window
+ AppDelegate.m:comments
+ AppDelegate.m:imports:importHeader:AppDelegate.h
+ AppDelegate.m:extension
+ AppDelegate.m:implementation:synthesize
+ AppDelegate.m:implementation:methods:applicationdidFinishLaunchingWithOptions(- (BOOL\)application:(UIApplication *\)application didFinishLaunchingWithOptions:(NSDictionary *\)launchOptions)
+ AppDelegate.m:implementation:methods:applicationdidFinishLaunchingWithOptions:body
+ AppDelegate.m:implementation:methods:applicationdidFinishLaunchingWithOptions:return
+ AppDelegate.m:implementation:methods:applicationWillResignActive(- (void\)applicationWillResignActive:(UIApplication *\)application)
+ AppDelegate.m:implementation:methods:applicationWillResignActive:comments
+ AppDelegate.m:implementation:methods:applicationDidEnterBackground(- (void\)applicationDidEnterBackground:(UIApplication *\)application)
+ AppDelegate.m:implementation:methods:applicationDidEnterBackground:comments
+ AppDelegate.m:implementation:methods:applicationWillEnterForeground(- (void\)applicationWillEnterForeground:(UIApplication *\)application)
+ AppDelegate.m:implementation:methods:applicationWillEnterForeground:comments
+ AppDelegate.m:implementation:methods:applicationDidBecomeActive(- (void\)applicationDidBecomeActive:(UIApplication *\)application)
+ AppDelegate.m:implementation:methods:applicationDidBecomeActive:comments
+ AppDelegate.m:implementation:methods:applicationWillTerminate(- (void\)applicationWillTerminate:(UIApplication *\)application)
+ AppDelegate.m:implementation:methods:applicationWillTerminate:comments
+
+ Definitions
+
+ main.m:main
+
+ Beginning
+ int main(int argc, char * argv[]) {
+ End
+ }
+ Indent
+ 1
+
+ main.m:main:UIApplicationMain
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+}
+
+ AppDelegate.h:interface:window
+ @property (strong, nonatomic) UIWindow *window;
+
+ AppDelegate.m:implementation:methods:applicationdidFinishLaunchingWithOptions:body
+ // Override point for customization after application launch.
+ AppDelegate.m:implementation:methods:applicationdidFinishLaunchingWithOptions:return
+ return YES;
+ *:implementation:methods:viewDidLoad:super
+ [super viewDidLoad];
+// Do any additional setup after loading the view, typically from a nib.
+ *:implementation:methods:didReceiveMemoryWarning:super
+ [super didReceiveMemoryWarning];
+// Dispose of any resources that can be recreated.
+
+
+ Swift
+
+ Nodes
+
+ Application/AppDelegate.swift
+
+ Definitions
+
+ Application/AppDelegate.swift
+
+ Group
+ Application
+ Path
+ AppDelegate.swift
+
+
+
+
+
+
+ Nodes
+
+ Info.plist
+ ../.gitignore
+ ../.swiftlint.yml
+ ../.swiftformat
+ ../Podfile
+ ../R.generated.swift
+ ../Gemfile
+ ../Rambafile
+ ../appcenter-post-clone.sh
+ Application/LaunchScreen.storyboard
+ Third Party/.gitkeep
+ Services/.gitkeep
+ Screens/.gitkeep
+ Resources/Assets.xcassets
+ Resources/Strings/Localizable.strings
+ Resources/Images/.gitkeep
+ Resources/Constants/ApiKeys.swift
+ Resources/Fonts/.gitkeep
+ Models/Presentation/.gitkeep
+ Library/Base Classes/.gitkeep
+ Library/Utils/.gitkeep
+ Library/Extensions/.gitkeep
+ Library/Reusable Layer/.gitkeep
+ Library/Protocols/ScreenTransitionable.swift
+
+ Definitions
+
+ Info.plist
+
+ Path
+ Info.plist
+ TargetIndices
+
+
+ ../R.generated.swift
+
+ Path
+ R.generated.swift
+ Group
+
+ Resources
+
+
+ ../.gitignore
+
+ Path
+ .gitignore
+ TargetIndices
+
+ Group
+
+ Non-iOS Resources
+
+
+ ../.swiftlint.yml
+
+ Path
+ .swiftlint.yml
+ TargetIndices
+
+ Group
+
+ Non-iOS Resources
+
+
+ ../.swiftformat
+
+ Path
+ .swiftformat
+ Group
+
+ Non-iOS Resources
+
+
+ ../Podfile
+
+ Path
+ Podfile
+ Group
+ Non-iOS Resources
+
+ ../Gemfile
+
+ Path
+ Gemfile
+ Group
+ Non-iOS Resources
+
+ ../Rambafile
+
+ TargetIndices
+
+ Path
+ Rambafile
+ Group
+ Non-iOS Resources
+
+ ../appcenter-post-clone.sh
+
+ TergetIndices
+
+ Path
+ appcenter-post-clone.sh
+ Group
+ Non-iOS Resources
+
+ Application/LaunchScreen.storyboard
+
+ Path
+ LaunchScreen.storyboard
+ Group
+ Application
+
+ Resources/Strings/Localizable.strings
+
+ Path
+ Localizable.strings
+ Group
+
+ Resources
+ Strings
+
+
+ Library/Base Classes/.gitkeep
+
+ Group
+
+ Library
+ Base Classes
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Library/Utils/.gitkeep
+
+ Group
+
+ Library
+ Utils
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Library/Extensions/.gitkeep
+
+ Group
+
+ Library
+ Extensions
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Library/Reusable Layer/.gitkeep
+
+ Group
+
+ Library
+ Reusable Layer
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Library/Protocols/.gitkeep
+
+ Group
+
+ Library
+ Protocols
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Models/Presentation/.gitkeep
+
+ Group
+
+ Models
+ Presentation
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Resources/Assets.xcassets
+
+ Path
+ Assets.xcassets
+ Group
+ Resources
+
+ Resources/Images/.gitkeep
+
+ Group
+
+ Resources
+ Images
+
+ Path
+ .gitkeep
+ TargetIndices
+
+
+ Resources/Constants/ApiKeys.swift
+
+ Group
+
+ Resources
+ Constants
+
+ Path
+ ApiKeys.swift
+
+ Resources/Fonts/.gitkeep
+
+ Group
+
+ Resources
+ Fonts
+
+ Path
+ ../.gitkeep
+ TargetIndices
+
+
+ Screens/.gitkeep
+
+ Group
+ Screens
+ Path
+ ../.gitkeep
+ TargetIndices
+
+
+ Services/.gitkeep
+
+ Group
+ Services
+ Path
+ ../.gitkeep
+ TargetIndices
+
+
+ Third Party/.gitkeep
+
+ Group
+ Third Party
+ Path
+ ../.gitkeep
+ TargetIndices
+
+
+ Library/Protocols/ScreenTransitionable.swift
+
+ Group
+
+ Library
+ Protocols
+
+ Path
+ ScreenTransitionable.swift
+
+
+ Targets
+
+
+ TargetIdentifier
+ com.apple.dt.cocoaTouchApplicationTarget
+ SharedSettings
+
+ LD_RUNPATH_SEARCH_PATHS
+ $(inherited) @executable_path/Frameworks
+ TARGETED_DEVICE_FAMILY
+ 1,2
+
+ BuildPhases
+
+
+ Class
+ ShellScript
+ ShellPath
+ /bin/sh
+ Name
+ R.swift
+ ShellScript
+ "$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift"
+ InputFiles
+
+ $TEMP_DIR/rswift-lastrun
+
+ OutputFiles
+
+ $SRCROOT/R.generated.swift
+
+
+
+ Class
+ ShellScript
+ ShellPath
+ /bin/sh
+ Name
+ SwiftLint
+ ShellScript
+ "${PODS_ROOT}/SwiftLint/swiftlint"
+
+
+ Class
+ ShellScript
+ ShellPath
+ /bin/sh
+ Name
+ SwiftFormat
+ ShellScript
+ "${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" "${SRCROOT}/___PACKAGENAME___" --swiftversion "${SWIFT_VERSION}"
+
+
+
+
+
+
diff --git a/HandsApp iOS App.xctemplate/appcenter-post-clone.sh b/HandsApp iOS App.xctemplate/appcenter-post-clone.sh
new file mode 100644
index 0000000..87f12b8
--- /dev/null
+++ b/HandsApp iOS App.xctemplate/appcenter-post-clone.sh
@@ -0,0 +1,10 @@
+
+#!/usr/bin/env bash
+
+echo "Uninstalling all CocoaPods versions"
+sudo gem uninstall cocoapods --all --executables
+
+COCOAPODS_VER=`sed -n -e 's/^COCOAPODS: \([0-9.]*\)/\1/p' Podfile.lock`
+
+echo "Installing CocoaPods version $COCOAPODS_VER"
+sudo gem install cocoapods -v $COCOAPODS_VER
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Single View App With Code Tools.xctemplate/TemplateIcon.png b/Single View App With Code Tools.xctemplate/TemplateIcon.png
deleted file mode 100755
index 1ac317e..0000000
Binary files a/Single View App With Code Tools.xctemplate/TemplateIcon.png and /dev/null differ
diff --git a/Single View App With Code Tools.xctemplate/TemplateIcon@2x.png b/Single View App With Code Tools.xctemplate/TemplateIcon@2x.png
deleted file mode 100755
index 904906e..0000000
Binary files a/Single View App With Code Tools.xctemplate/TemplateIcon@2x.png and /dev/null differ
diff --git a/Single View App With Code Tools.xctemplate/TemplateInfo.plist b/Single View App With Code Tools.xctemplate/TemplateInfo.plist
deleted file mode 100644
index edacd11..0000000
--- a/Single View App With Code Tools.xctemplate/TemplateInfo.plist
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
-
- Kind
- Xcode.Xcode3.ProjectTemplateUnitKind
- Identifier
- cc.ovchinnikov.dt.unit.singleViewApplicationWithCodeTools
- Ancestors
-
- com.apple.dt.unit.storyboardApplication
- com.apple.dt.unit.coreDataCocoaTouchApplication
-
- Concrete
-
- Description
- This template is a copy of default Single View Application template, but it comes with .gitignore, SwiftLint, SwiftFormat, R.swift and script for bootstraping all this stuff with CocoaPods.
- SortOrder
- 1
- Options
-
-
- Identifier
- languageChoice
- Units
-
- Objective-C
-
- Nodes
-
- ViewController.h:comments
- ViewController.h:imports:importCocoa
- ViewController.h:interface(___FILEBASENAME___ : UIViewController)
- ViewController.m:comments
- ViewController.m:imports:importHeader:ViewController.h
- ViewController.m:extension
- ViewController.m:implementation:methods:viewDidLoad(- (void\)viewDidLoad)
- ViewController.m:implementation:methods:viewDidLoad:super
-
-
- Swift
-
- Nodes
-
- ViewController.swift:comments
- ViewController.swift:imports:importCocoa
- ViewController.swift:implementation(___FILEBASENAME___: UIViewController)
- ViewController.swift:implementation:methods:viewDidLoad(override func viewDidLoad(\))
- ViewController.swift:implementation:methods:viewDidLoad:super
-
-
-
-
-
- Definitions
-
- Base.lproj/Main.storyboard
-
- Path
- Main.storyboard
- SortOrder
- 99
-
- ../R.generated.swift
-
- Path
- R.generated.swift
- SortOrder
- 99
-
- ../.gitignore
-
- Path
- .gitignore
- TargetIndices
-
- Group
-
- Non-iOS Resources
-
-
- ../.swiftlint.yml
-
- Path
- .swiftlint.yml
- TargetIndices
-
- Group
-
- Non-iOS Resources
-
-
- ../Podfile
-
- TargetIndices
-
- Beginning
- use_frameworks!
-inhibit_all_warnings!
-
-platform :ios, '12.0'
-
-target '___PACKAGENAME___' do
- pod 'R.swift'
- pod 'SwiftFormat/CLI'
- pod 'SwiftLint'
-
- End
-
-end
-
- Group
-
- Non-iOS Resources
-
-
-
- Nodes
-
- ../.gitignore
- ../.swiftlint.yml
- ../Podfile
- ../R.generated.swift
-
- Targets
-
-
- BuildPhases
-
-
- Class
- ShellScript
- ShellPath
- /bin/sh
- Name
- R.swift
- ShellScript
- "$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift"
- InputFiles
-
- $TEMP_DIR/rswift-lastrun
-
- OutputFiles
-
- $SRCROOT/R.generated.swift
-
-
-
- Class
- ShellScript
- ShellPath
- /bin/sh
- Name
- SwiftLint
- ShellScript
- "${PODS_ROOT}/SwiftLint/swiftlint"
-
-
- Class
- ShellScript
- ShellPath
- /bin/sh
- Name
- SwiftFormat
- ShellScript
- "${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" "${SRCROOT}/___PACKAGENAME___" --swiftversion "${SWIFT_VERSION}"
-
-
-
-
-
-
diff --git a/images/choosing_project_template.png b/images/choosing_project_template.png
deleted file mode 100644
index e222717..0000000
Binary files a/images/choosing_project_template.png and /dev/null differ
diff --git a/install_empty_swift_file_template.sh b/install_empty_swift_file_template.sh
new file mode 100755
index 0000000..a9f1c42
--- /dev/null
+++ b/install_empty_swift_file_template.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o errtrace
+
+TEMPLATE_DIR=${HOME}/"Library/Developer/Xcode/Templates/File Templates/Source"
+TEMPLATE_NAME="Empty Swift File.xctemplate"
+
+if [ ! -d "$TEMPLATE_DIR" ]; then
+ echo "Didn't find a directory for the templates, so creating it..."
+ mkdir -p "${TEMPLATE_DIR}"
+ echo "Created $TEMPLATE_DIR"
+fi
+
+if [ -d "$TEMPLATE_DIR/$TEMPLATE_NAME" ]; then
+ echo "Delete previously created templates..."
+ rm -rf "$TEMPLATE_DIR/$TEMPLATE_NAME"
+ echo "Deleted $TEMPLATE_DIR/$TEMPLATE_NAME"
+fi
+
+echo "Copying template files..."
+cp -rf "./$TEMPLATE_NAME" "$TEMPLATE_DIR"
+echo "Done."
diff --git a/install.sh b/install_handsapp_ios_app_template.sh
similarity index 57%
rename from install.sh
rename to install_handsapp_ios_app_template.sh
index ac7c990..fd42d70 100755
--- a/install.sh
+++ b/install_handsapp_ios_app_template.sh
@@ -3,8 +3,8 @@
set -o errexit
set -o errtrace
-TEMPLATE_DIR=${HOME}/"Library/Developer/Xcode/Templates/Project Templates/Private"
-TEMPLATE_NAME="Single View App With Code Tools.xctemplate"
+TEMPLATE_DIR=${HOME}/"Library/Developer/Xcode/Templates/Project Templates/HandsApp"
+TEMPLATE_NAME="HandsApp iOS App.xctemplate"
if [ ! -d "$TEMPLATE_DIR" ]; then
echo "Didn't find a directory for the templates, so creating it..."
@@ -12,6 +12,12 @@ if [ ! -d "$TEMPLATE_DIR" ]; then
echo "Created $TEMPLATE_DIR"
fi
+if [ -d "$TEMPLATE_DIR/$TEMPLATE_NAME" ]; then
+ echo "Delete previously created templates..."
+ rm -rf "$TEMPLATE_DIR/$TEMPLATE_NAME"
+ echo "Deleted $TEMPLATE_DIR/$TEMPLATE_NAME"
+fi
+
echo "Copying template files..."
cp -rf "./$TEMPLATE_NAME" "$TEMPLATE_DIR"
-echo "Done."
\ No newline at end of file
+echo "Done."
diff --git a/install_handsapp_network_ios_app_template.sh b/install_handsapp_network_ios_app_template.sh
new file mode 100755
index 0000000..a6650c0
--- /dev/null
+++ b/install_handsapp_network_ios_app_template.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o errtrace
+
+TEMPLATE_DIR=${HOME}/"Library/Developer/Xcode/Templates/Project Templates/HandsApp"
+PARENT_TEMPLATE_NAME="HandsApp iOS App.xctemplate"
+TEMPLATE_NAME="HandsApp Network iOS App.xctemplate"
+
+if [ ! -d "$TEMPLATE_DIR" ]; then
+ echo "Didn't find a directory for the templates, so creating it..."
+ mkdir -p "${TEMPLATE_DIR}"
+ echo "Created $TEMPLATE_DIR"
+fi
+
+if [ -d "$TEMPLATE_DIR/$TEMPLATE_NAME" ]; then
+ echo "Delete previously created templates..."
+ rm -rf "$TEMPLATE_DIR/$TEMPLATE_NAME"
+ echo "Deleted $TEMPLATE_DIR/$TEMPLATE_NAME"
+fi
+
+if [ -d "$TEMPLATE_DIR/$PARENT_TEMPLATE_NAME" ]; then
+ echo "Delete previously created templates..."
+ rm -rf "$TEMPLATE_DIR/$PARENT_TEMPLATE_NAME"
+ echo "Deleted $TEMPLATE_DIR/$PARENT_TEMPLATE_NAME"
+fi
+
+echo "Copying template files..."
+cp -rf "./$PARENT_TEMPLATE_NAME" "$TEMPLATE_DIR"
+cp -rf "./$TEMPLATE_NAME" "$TEMPLATE_DIR"
+
+echo "Done."
diff --git a/readme.md b/readme.md
index ba51b4d..659a248 100644
--- a/readme.md
+++ b/readme.md
@@ -6,33 +6,42 @@ This repository contains useful Xcode templates to simplify new projects up and
Clone this project and navigate to it via terminal. Run install script:
- chmod +x install.sh
- ./install.sh
+ chmod +x install_handsapp_ios_app_template.sh
+ ./install_handsapp_ios_app_template.sh
-This script will copy the templates to `~/Library/Developer/Xcode/Templates/Project Templates/Private` where Xcode will be able to find them.
+This script will copy HandsApp project template to `~/Library/Developer/Xcode/Templates/Project Templates/HandsApp` where Xcode will be able to find it.
+
+ chmod +x install_empty_swift_file_template.sh
+ ./install_empty_swift_file_template.sh
+
+This script will copy empty file template to `~/Library/Developer/Xcode/Templates/File Templates/Source` where Xcode will be able to find it.
## Templates usage
-### Single View App With Code Tools
+### Empty Swift File Template
+
+This template creates blank Swift file without headers and imports.
-This template is a copy of default *Single View App* Xcode template with several handy additions:
+### HandsApp iOS App Template
+
+This template creates iOS project with [SurfMVP](https://github.com/surfstudio/Surf-iOS-Developers/blob/master/Surf_MVP.md) structure with some userful features:
* `.gitignore` file;
* [SwiftLint](https://github.com/realm/SwiftLint) build phase integration and configuration file;
* [SwiftFormat](https://github.com/nicklockwood/SwiftFormat) build phase integration;
* [R.Swift](https://github.com/mac-cain13/R.swift) build phase integration;
-* `Podfile` to install all the tools mentioned above.
+* `Podfile` to install all the tools mentioned above;
+* [Generamba](https://github.com/strongself/Generamba) code generator;
+* `Gemfile` to install Generamba and Cocoapods.
#### Up and running
-1. Open Xcode and create new project, choose *Single View App With Code Tools* from the wizard (at the *Private* section);
- 
+1. Open Xcode and create new project, choose *HandsApp iOS App Template* from the wizard (at the *Private* section);
2. Configure project name and other parameters as usual;
-3. Close project, navigate to it via terminal and run `pod install` to install the dependencies;
-4. Open the generated workspace, navigate to *Build Phases* of your project's main target and **move the SwiftFormat, SwiftLint, and R.Swift script phases above the compile phase** (exactly that order). We have to make this step manually due to limitations of Xcode templates;
+3. Close project, navigate to it via terminal and run `bundle install` to install gems. If you have no *Bundler* installed - welcome here https://bundler.io/
+4. Run `pod install` to install pods;
+5. Open the generated workspace, navigate to *Build Phases* of your project's main target and **move the SwiftFormat, SwiftLint, and R.Swift script phases above the compile phase** (exactly that order). We have to make this step manually due to limitations of Xcode templates;

-5. Build project and have fun!
-
-## References
-
-Developing Xcode templates without documentation is hard, so kudos to [Vokal's templates repository](https://github.com/vokal/Xcode-Template) where I was able to find some answers to my questions.
\ No newline at end of file
+6. Remove automaticaly generated tests boilerplate file `{project_name}Tests\{project_name}Tests.swift`
+6. Configure Generamba and setup templates: `generamba template install`
+7. Build project