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); - ![Choosing project template](images/choosing_project_template.png) +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; ![Build phases configuration](images/build_phases_configuration.png) -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