diff --git a/CHANGES.rst b/CHANGES.rst index 835b55239..1c0af777e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changes in 0.8.5 (2019-xx-xx) Improvements: * Push: Add more logs to track spontaneously disabling (#2348). * Widgets: Use scalar prod urls in Riot mobile apps (#2349). + * Productiviy: Create templates (see Tools/Templates/README.md). Bug fix: * Share extension: Fix a crash when receive a memory warning (PR #2352). diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index f4f6d4f54..13c95d8fc 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -22,6 +22,20 @@ 32242F1721E8FBE500725742 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32242F0D21E8FBA900725742 /* Theme.swift */; }; 32242F1821E8FBF800725742 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32242F0F21E8FBA900725742 /* DefaultTheme.swift */; }; 32242F1921E8FBFB00725742 /* DarkTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32242F1021E8FBA900725742 /* DarkTheme.swift */; }; + 3232AB1422564D9100AD6A5C /* swiftgen-config.yml in Resources */ = {isa = PBXBuildFile; fileRef = 3232AB0022564D9100AD6A5C /* swiftgen-config.yml */; }; + 3232AB1522564D9100AD6A5C /* flat-swift4-vector.stencil in Resources */ = {isa = PBXBuildFile; fileRef = 3232AB0322564D9100AD6A5C /* flat-swift4-vector.stencil */; }; + 3232AB2122564D9100AD6A5C /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 3232AB1322564D9100AD6A5C /* README.md */; }; + 3232AB482256558300AD6A5C /* FlowTemplateCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB3C2256558300AD6A5C /* FlowTemplateCoordinatorType.swift */; }; + 3232AB492256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB3D2256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift */; }; + 3232AB4A2256558300AD6A5C /* FlowTemplateCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB3E2256558300AD6A5C /* FlowTemplateCoordinator.swift */; }; + 3232AB4B2256558300AD6A5C /* TemplateScreenViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3232AB402256558300AD6A5C /* TemplateScreenViewController.storyboard */; }; + 3232AB4C2256558300AD6A5C /* TemplateScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB412256558300AD6A5C /* TemplateScreenCoordinator.swift */; }; + 3232AB4D2256558300AD6A5C /* TemplateScreenCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB422256558300AD6A5C /* TemplateScreenCoordinatorType.swift */; }; + 3232AB4E2256558300AD6A5C /* TemplateScreenViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB432256558300AD6A5C /* TemplateScreenViewModelType.swift */; }; + 3232AB4F2256558300AD6A5C /* TemplateScreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB442256558300AD6A5C /* TemplateScreenViewController.swift */; }; + 3232AB502256558300AD6A5C /* TemplateScreenViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB452256558300AD6A5C /* TemplateScreenViewState.swift */; }; + 3232AB512256558300AD6A5C /* TemplateScreenViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB462256558300AD6A5C /* TemplateScreenViewAction.swift */; }; + 3232AB522256558300AD6A5C /* TemplateScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3232AB472256558300AD6A5C /* TemplateScreenViewModel.swift */; }; 3233F7461F3497E2006ACA81 /* JitsiMeet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */; }; 3233F7471F3497E2006ACA81 /* JitsiMeet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3275FD8C21A5A2C500B9C13D /* TermsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3275FD8B21A5A2C500B9C13D /* TermsView.swift */; }; @@ -477,6 +491,20 @@ 32242F0F21E8FBA900725742 /* DefaultTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = ""; }; 32242F1021E8FBA900725742 /* DarkTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkTheme.swift; sourceTree = ""; }; 32242F1121E8FBA900725742 /* ThemeService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThemeService.h; sourceTree = ""; }; + 3232AB0022564D9100AD6A5C /* swiftgen-config.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "swiftgen-config.yml"; sourceTree = ""; }; + 3232AB0322564D9100AD6A5C /* flat-swift4-vector.stencil */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "flat-swift4-vector.stencil"; sourceTree = ""; }; + 3232AB1322564D9100AD6A5C /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 3232AB3C2256558300AD6A5C /* FlowTemplateCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlowTemplateCoordinatorType.swift; sourceTree = ""; }; + 3232AB3D2256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlowTemplateCoordinatorBridgePresenter.swift; sourceTree = ""; }; + 3232AB3E2256558300AD6A5C /* FlowTemplateCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlowTemplateCoordinator.swift; sourceTree = ""; }; + 3232AB402256558300AD6A5C /* TemplateScreenViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TemplateScreenViewController.storyboard; sourceTree = ""; }; + 3232AB412256558300AD6A5C /* TemplateScreenCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinator.swift; sourceTree = ""; }; + 3232AB422256558300AD6A5C /* TemplateScreenCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinatorType.swift; sourceTree = ""; }; + 3232AB432256558300AD6A5C /* TemplateScreenViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModelType.swift; sourceTree = ""; }; + 3232AB442256558300AD6A5C /* TemplateScreenViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewController.swift; sourceTree = ""; }; + 3232AB452256558300AD6A5C /* TemplateScreenViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewState.swift; sourceTree = ""; }; + 3232AB462256558300AD6A5C /* TemplateScreenViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewAction.swift; sourceTree = ""; }; + 3232AB472256558300AD6A5C /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = ""; }; 3233F7441F3497DA006ACA81 /* JitsiMeet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = ""; }; 3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = ""; }; 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; fileEncoding = 4; path = Podfile; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; @@ -1161,6 +1189,83 @@ path = Themes; sourceTree = ""; }; + 3232AAFE22564D9100AD6A5C /* Tools */ = { + isa = PBXGroup; + children = ( + 3232AAFF22564D9100AD6A5C /* SwiftGen */, + 3232AB0422564D9100AD6A5C /* Templates */, + ); + path = Tools; + sourceTree = ""; + }; + 3232AAFF22564D9100AD6A5C /* SwiftGen */ = { + isa = PBXGroup; + children = ( + 3232AB0022564D9100AD6A5C /* swiftgen-config.yml */, + 3232AB0122564D9100AD6A5C /* Templates */, + ); + path = SwiftGen; + sourceTree = ""; + }; + 3232AB0122564D9100AD6A5C /* Templates */ = { + isa = PBXGroup; + children = ( + 3232AB0222564D9100AD6A5C /* Strings */, + ); + path = Templates; + sourceTree = ""; + }; + 3232AB0222564D9100AD6A5C /* Strings */ = { + isa = PBXGroup; + children = ( + 3232AB0322564D9100AD6A5C /* flat-swift4-vector.stencil */, + ); + path = Strings; + sourceTree = ""; + }; + 3232AB0422564D9100AD6A5C /* Templates */ = { + isa = PBXGroup; + children = ( + 3232AB1322564D9100AD6A5C /* README.md */, + 3232AB0522564D9100AD6A5C /* buildable */, + ); + path = Templates; + sourceTree = ""; + }; + 3232AB0522564D9100AD6A5C /* buildable */ = { + isa = PBXGroup; + children = ( + 3232AB3B2256558300AD6A5C /* FlowCoordinatorTemplate */, + 3232AB3F2256558300AD6A5C /* ScreenTemplate */, + ); + path = buildable; + sourceTree = ""; + }; + 3232AB3B2256558300AD6A5C /* FlowCoordinatorTemplate */ = { + isa = PBXGroup; + children = ( + 3232AB3C2256558300AD6A5C /* FlowTemplateCoordinatorType.swift */, + 3232AB3D2256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift */, + 3232AB3E2256558300AD6A5C /* FlowTemplateCoordinator.swift */, + ); + path = FlowCoordinatorTemplate; + sourceTree = ""; + }; + 3232AB3F2256558300AD6A5C /* ScreenTemplate */ = { + isa = PBXGroup; + children = ( + 3232AB402256558300AD6A5C /* TemplateScreenViewController.storyboard */, + 3232AB412256558300AD6A5C /* TemplateScreenCoordinator.swift */, + 3232AB422256558300AD6A5C /* TemplateScreenCoordinatorType.swift */, + 3232AB432256558300AD6A5C /* TemplateScreenViewModelType.swift */, + 3232AB442256558300AD6A5C /* TemplateScreenViewController.swift */, + 3232AB452256558300AD6A5C /* TemplateScreenViewState.swift */, + 3232AB462256558300AD6A5C /* TemplateScreenViewAction.swift */, + 3232AB472256558300AD6A5C /* TemplateScreenViewModel.swift */, + ); + path = ScreenTemplate; + sourceTree = ""; + }; 3233F7291F31F3B4006ACA81 /* libs */ = { isa = PBXGroup; children = ( @@ -2920,6 +3025,7 @@ F094A9A31B78D8F000B1FBBF /* Products */, 5FC42FA41F5186AFFB6A2404 /* Frameworks */, A237FB70534FB8ADA0D7CFEE /* Pods */, + 3232AAFE22564D9100AD6A5C /* Tools */, ); sourceTree = ""; usesTabs = 0; @@ -3076,6 +3182,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, nl, @@ -3193,17 +3300,21 @@ B1B5573720EE6C4D00210D55 /* GroupParticipantsViewController.xib in Resources */, B110872421F098F0003554A5 /* ActivityIndicatorView.xib in Resources */, B1B5573320EE6C4D00210D55 /* GroupHomeViewController.xib in Resources */, + 3232AB2122564D9100AD6A5C /* README.md in Resources */, B1B5593920EF7BAC00210D55 /* TableViewCellWithCheckBoxes.xib in Resources */, B1B557C120EF5B4500210D55 /* DisabledRoomInputToolbarView.xib in Resources */, B1664DA320F4F96200808783 /* Vector.strings in Resources */, B1B557C720EF5CD400210D55 /* DirectoryServerDetailTableViewCell.xib in Resources */, B1B5582620EF638A00210D55 /* RoomMemberTitleView.xib in Resources */, + 3232AB1522564D9100AD6A5C /* flat-swift4-vector.stencil in Resources */, F083BDE61E7009ED00A9B29C /* busy.mp3 in Resources */, B1B5574C20EE6C4D00210D55 /* MediaAlbumContentViewController.xib in Resources */, B1B557E820EF60F500210D55 /* MessagesSearchResultTextMsgBubbleCell.xib in Resources */, B1B558D920EF768F00210D55 /* RoomOutgoingEncryptedAttachmentBubbleCell.xib in Resources */, B1B5573020EE6C4D00210D55 /* BugReportViewController.xib in Resources */, B169329B20F39E6300746532 /* Main.storyboard in Resources */, + 3232AB1422564D9100AD6A5C /* swiftgen-config.yml in Resources */, + 3232AB4B2256558300AD6A5C /* TemplateScreenViewController.storyboard in Resources */, 32B1FEDB21A46F2C00637127 /* TermsView.xib in Resources */, B1B5578E20EF568D00210D55 /* GroupInviteTableViewCell.xib in Resources */, B1B5582020EF625800210D55 /* SimpleRoomTitleView.xib in Resources */, @@ -3467,6 +3578,7 @@ B1FDF56021F5FE5500BA3834 /* KeyBackupSetupPassphraseViewAction.swift in Sources */, B1B5573120EE6C4D00210D55 /* BugReportViewController.m in Sources */, B16932A520F3A21C00746532 /* empty.mm in Sources */, + 3232AB4A2256558300AD6A5C /* FlowTemplateCoordinator.swift in Sources */, B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */, B16932FA20F3C51A00746532 /* RecentCellData.m in Sources */, B16932F220F3C49E00746532 /* GroupsDataSource.m in Sources */, @@ -3479,6 +3591,7 @@ B16932B120F3AC9200746532 /* RoomSearchDataSource.m in Sources */, B16932A320F3A21C00746532 /* main.m in Sources */, B1B5574520EE6C4D00210D55 /* StartChatViewController.m in Sources */, + 3232AB4C2256558300AD6A5C /* TemplateScreenCoordinator.swift in Sources */, B1B5575920EE6C4D00210D55 /* HomeMessagesSearchViewController.m in Sources */, B1B558DE20EF768F00210D55 /* RoomIncomingAttachmentBubbleCell.m in Sources */, B1B5574820EE6C4D00210D55 /* PeopleViewController.m in Sources */, @@ -3499,6 +3612,7 @@ B1B5572320EE6C4D00210D55 /* AttachmentsViewController.m in Sources */, F083BDEE1E7009ED00A9B29C /* MXRoom+Riot.m in Sources */, B1B5598620EFC3E000210D55 /* RiotSettings.swift in Sources */, + 3232AB4D2256558300AD6A5C /* TemplateScreenCoordinatorType.swift in Sources */, B1B5581720EF625800210D55 /* PreviewRoomTitleView.m in Sources */, B1098BDF21ECE09F000DDA48 /* Strings.swift in Sources */, B1B558C420EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, @@ -3546,6 +3660,8 @@ B169330020F3C97D00746532 /* RoomDataSource.m in Sources */, B1B558ED20EF768F00210D55 /* RoomIncomingTextMsgWithoutSenderNameBubbleCell.m in Sources */, B1B5571920EE6C4D00210D55 /* LanguagePickerViewController.m in Sources */, + 3232AB512256558300AD6A5C /* TemplateScreenViewAction.swift in Sources */, + 3232AB4E2256558300AD6A5C /* TemplateScreenViewModelType.swift in Sources */, B1B5590520EF768F00210D55 /* RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m in Sources */, B1B558DD20EF768F00210D55 /* RoomIncomingEncryptedTextMsgBubbleCell.m in Sources */, B1098BE521ECE1FC000DDA48 /* Storyboards.swift in Sources */, @@ -3567,6 +3683,7 @@ B139C21D21FE5BF500BB68EC /* KeyBackupRecoverFromPassphraseViewModelType.swift in Sources */, F083BE031E7009ED00A9B29C /* EventFormatter.m in Sources */, B16932F720F3C50E00746532 /* RecentsDataSource.m in Sources */, + 3232AB4F2256558300AD6A5C /* TemplateScreenViewController.swift in Sources */, B1B558FC20EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */, B1B5572920EE6C4D00210D55 /* RoomFilesViewController.m in Sources */, B1098C1021ED07E4000DDA48 /* Presentable.swift in Sources */, @@ -3637,11 +3754,13 @@ B17982FF2119FED2001FD722 /* GDPRConsentViewController.swift in Sources */, B1098BE121ECE09F000DDA48 /* Images.swift in Sources */, B1B5575A20EE6C4D00210D55 /* UnifiedSearchViewController.m in Sources */, + 3232AB492256558300AD6A5C /* FlowTemplateCoordinatorBridgePresenter.swift in Sources */, B1B5572820EE6C4D00210D55 /* RoomViewController.m in Sources */, B1B558C720EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */, B1B558F020EF768F00210D55 /* RoomOutgoingAttachmentWithPaginationTitleBubbleCell.m in Sources */, 926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */, B1B5593820EF7BAC00210D55 /* TableViewCellWithLabelAndLargeTextView.m in Sources */, + 3232AB502256558300AD6A5C /* TemplateScreenViewState.swift in Sources */, B1B558C820EF768F00210D55 /* RoomIncomingEncryptedAttachmentBubbleCell.m in Sources */, B1B557C620EF5CD400210D55 /* DirectoryServerDetailTableViewCell.m in Sources */, B1B5590920EF768F00210D55 /* RoomEmptyBubbleCell.m in Sources */, @@ -3683,10 +3802,12 @@ B1B5574920EE6C4D00210D55 /* RiotSplitViewController.m in Sources */, B1B5574E20EE6C4D00210D55 /* DirectoryServerPickerViewController.m in Sources */, B1DB4F0B223131600065DBFA /* String.swift in Sources */, + 3232AB522256558300AD6A5C /* TemplateScreenViewModel.swift in Sources */, B1B5575B20EE6C4D00210D55 /* HomeFilesSearchViewController.m in Sources */, B139C22521FF01C100BB68EC /* KeyBackupRecoverFromPassphraseCoordinator.swift in Sources */, B1098BFD21ECFE65000DDA48 /* PasswordStrengthManager.swift in Sources */, B1B558F520EF768F00210D55 /* RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m in Sources */, + 3232AB482256558300AD6A5C /* FlowTemplateCoordinatorType.swift in Sources */, B1B558F820EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, 32242F0921E8B05F00725742 /* UIColor.swift in Sources */, B16932E720F3C37100746532 /* HomeMessagesSearchDataSource.m in Sources */, diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index afafd57f1..80f0725b6 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -47,6 +47,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self) } + internal enum TemplateScreenViewController: StoryboardType { + internal static let storyboardName = "TemplateScreenViewController" + + internal static let initialScene = InitialSceneType(storyboard: TemplateScreenViewController.self) + } } // swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name diff --git a/Tools/SwiftGen/swiftgen-config.yml b/Tools/SwiftGen/swiftgen-config.yml index 7da2a05f6..bb711f244 100755 --- a/Tools/SwiftGen/swiftgen-config.yml +++ b/Tools/SwiftGen/swiftgen-config.yml @@ -1,8 +1,10 @@ input_dir: ../../Riot/ output_dir: ../../Riot/Generated/ ib: - - inputs: - - Modules/KeyBackup/ + - inputs: + - ../Tools/Templates/buildable/ + - Modules/ + filter: ^((?!DeactivateAccountViewController).)*\.(storyboard) outputs: - templateName: scenes-swift4 output: Storyboards.swift diff --git a/Tools/Templates/README.md b/Tools/Templates/README.md new file mode 100644 index 000000000..54e33f1aa --- /dev/null +++ b/Tools/Templates/README.md @@ -0,0 +1,56 @@ +The `buildable` folder contains templates with source files that build. + +The goal is to turn these templates as Xcode templates. They are part of the Riot project in order to ensure they build + +# ScreenTemplate +This is the boilerplate to create a screen that follows the MVVM-C pattern used within the Riot app. + +To create a screen from this template (before it becomes an Xcode template): + +- `./createScreen.sh ScreenFolder MyScreenName` +- Import the created folder in the Xcode project + +This will create ScreenFolder within the Riot/Modules. Files inside will be named `MyScreenNameXxx`. + + +# FlowCoordinatorTemplate +The boilerplate to create a root coordinator and its presenter bridge that can be used from Objective-C. + +To use it (before it becomes an Xcode template): + +- `./createRootCoordinator.sh Folder MyRootCoordinatorName [DefaultScreenName]` +- Import created files in the Xcode project + + +# Usage example +Following commands: + +``` +./createScreen.sh MyFlowDir/MyFirstScreenDir MyFirstScreen +./createRootCoordinator.sh MyFlowDir MyFlow MyFirstScreen +``` + +generate in `Riot/Modules`: + +``` +Riot/Modules/MyFlowDir +├── MyFirstScreenDir +│   ├── MyFirstScreenCoordinator.swift +│   ├── MyFirstScreenCoordinatorType.swift +│   ├── MyFirstScreenViewAction.swift +│   ├── MyFirstScreenViewController.storyboard +│   ├── MyFirstScreenViewController.swift +│   ├── MyFirstScreenViewModel.swift +│   ├── MyFirstScreenViewModelType.swift +│   └── MyFirstScreenViewState.swift +├── MyFlowCoordinator.swift +├── MyFlowCoordinatorBridgePresenter.swift +└── MyFlowCoordinatorType.swift +``` + +The generated code is ready to use. The screen provided by `ScreenTemplate` can by displayed by: + +``` +MyFlowCoordinatorBridgePresenter *presenter = [[MyFlowCoordinatorBridgePresenter alloc] initWithSession:session]; +[presenter presentFrom:self animated:YES]; +``` diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift new file mode 100644 index 000000000..720ed34f4 --- /dev/null +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinator.swift @@ -0,0 +1,78 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import UIKit + +@objcMembers +final class FlowTemplateCoordinator: FlowTemplateCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let navigationRouter: NavigationRouterType + private let session: MXSession + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: FlowTemplateCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController()) + self.session = session + } + + // MARK: - Public methods + + func start() { + + let rootCoordinator = self.createTemplateScreenCoordinator() + + rootCoordinator.start() + + self.add(childCoordinator: rootCoordinator) + + self.navigationRouter.setRootModule(rootCoordinator) + } + + func toPresentable() -> UIViewController { + return self.navigationRouter.toPresentable() + } + + // MARK: - Private methods + + private func createTemplateScreenCoordinator() -> TemplateScreenCoordinator { + let coordinator = TemplateScreenCoordinator(session: self.session) + coordinator.delegate = self + return coordinator + } +} + +// MARK: - TemplateScreenCoordinatorDelegate +extension FlowTemplateCoordinator: TemplateScreenCoordinatorDelegate { + func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithMessage message: String) { + self.delegate?.flowTemplateCoordinatorDidComplete(self) + } + + func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorType) { + self.delegate?.flowTemplateCoordinatorDidComplete(self) + } +} diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift new file mode 100644 index 000000000..042c29106 --- /dev/null +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorBridgePresenter.swift @@ -0,0 +1,77 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +@objc protocol FlowTemplateCoordinatorBridgePresenterDelegate { + func flowTemplateCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: FlowTemplateCoordinatorBridgePresenter) +} + +/// FlowTemplateCoordinatorBridgePresenter enables to start FlowTemplateCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +@objcMembers +final class FlowTemplateCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var coordinator: FlowTemplateCoordinator? + + // MARK: Public + + weak var delegate: FlowTemplateCoordinatorBridgePresenterDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + super.init() + } + + // MARK: - Public + + // NOTE: Default value feature is not compatible with Objective-C. + // func present(from viewController: UIViewController, animated: Bool) { + // self.present(from: viewController, animated: animated) + // } + + func present(from viewController: UIViewController, animated: Bool) { + let flowTemplateCoordinator = FlowTemplateCoordinator(session: self.session) + flowTemplateCoordinator.delegate = self + viewController.present(flowTemplateCoordinator.toPresentable(), animated: animated, completion: nil) + flowTemplateCoordinator.start() + + self.coordinator = flowTemplateCoordinator + } + + func dismiss(animated: Bool) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + } + } +} + +// MARK: - FlowTemplateCoordinatorDelegate +extension FlowTemplateCoordinatorBridgePresenter: FlowTemplateCoordinatorDelegate { + func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorType) { + self.delegate?.flowTemplateCoordinatorBridgePresenterDelegateDidComplete(self) + } +} diff --git a/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift new file mode 100644 index 000000000..cd754d8d4 --- /dev/null +++ b/Tools/Templates/buildable/FlowCoordinatorTemplate/FlowTemplateCoordinatorType.swift @@ -0,0 +1,26 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +protocol FlowTemplateCoordinatorDelegate: class { + func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorType) +} + +/// `FlowTemplateCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. +protocol FlowTemplateCoordinatorType: Coordinator, Presentable { + var delegate: FlowTemplateCoordinatorDelegate? { get } +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift new file mode 100644 index 000000000..8cd322e45 --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinator.swift @@ -0,0 +1,69 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation +import UIKit + +final class TemplateScreenCoordinator: TemplateScreenCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + private var templateScreenViewModel: TemplateScreenViewModelType + private let templateScreenViewController: TemplateScreenViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: TemplateScreenCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + + let templateScreenViewModel = TemplateScreenViewModel(session: self.session) + let templateScreenViewController = TemplateScreenViewController.instantiate(with: templateScreenViewModel) + self.templateScreenViewModel = templateScreenViewModel + self.templateScreenViewController = templateScreenViewController + } + + // MARK: - Public methods + + func start() { + self.templateScreenViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.templateScreenViewController + } +} + +// MARK: - TemplateScreenViewModelCoordinatorDelegate +extension TemplateScreenCoordinator: TemplateScreenViewModelCoordinatorDelegate { + + func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithMessage message: String) { + self.delegate?.templateScreenCoordinator(self, didCompleteWithMessage: message) + } + + func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType) { + self.delegate?.templateScreenCoordinatorDidCancel(self) + } +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift new file mode 100644 index 000000000..b8869aafd --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenCoordinatorType.swift @@ -0,0 +1,27 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +protocol TemplateScreenCoordinatorDelegate: class { + func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithMessage message: String) + func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorType) +} + +/// `TemplateScreenCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol TemplateScreenCoordinatorType: Coordinator, Presentable { + var delegate: TemplateScreenCoordinatorDelegate? { get } +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift new file mode 100644 index 000000000..8dca49e5c --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewAction.swift @@ -0,0 +1,24 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +/// TemplateScreenViewController view actions exposed to view model +enum TemplateScreenViewAction { + case sayHello + case complete + case cancel +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.storyboard b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.storyboard new file mode 100644 index 000000000..35b09e221 --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.storyboard @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift new file mode 100644 index 000000000..4d1e3b3c6 --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewController.swift @@ -0,0 +1,185 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import UIKit + +final class TemplateScreenViewController: UIViewController { + + // MARK: - Constants + + private enum Constants { + static let aConstant: Int = 666 + } + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var scrollView: UIScrollView! + + @IBOutlet private weak var messageLabel: UILabel! + @IBOutlet private weak var okButton: UIButton! + + // MARK: Private + + private var viewModel: TemplateScreenViewModelType! + private var theme: Theme! + private var keyboardAvoider: KeyboardAvoider? + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: - Setup + + class func instantiate(with viewModel: TemplateScreenViewModelType) -> TemplateScreenViewController { + let viewController = StoryboardScene.TemplateScreenViewController.initialScene.instantiate() + viewController.viewModel = viewModel + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = "Template" + + self.setupViews() + self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.viewModel.viewDelegate = self + + self.viewModel.process(viewAction: .sayHello) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.keyboardAvoider?.startAvoiding() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + self.keyboardAvoider?.stopAvoiding() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + + // TODO: + self.messageLabel.textColor = theme.textPrimaryColor + + self.okButton.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.okButton) + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in + self?.cancelButtonAction() + } + + self.navigationItem.rightBarButtonItem = cancelBarButtonItem + + self.scrollView.keyboardDismissMode = .interactive + + self.messageLabel.text = "VectorL10n.templateScreenTitle" + self.messageLabel.isHidden = true + } + + private func render(viewState: TemplateScreenViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded: + self.renderLoaded() + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + + private func renderLoaded() { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + + self.messageLabel.text = self.viewModel.message + self.messageLabel.isHidden = false + } + + private func render(error: Error) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) + } + + + // MARK: - Actions + + @IBAction private func okButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .complete) + } + + private func cancelButtonAction() { + self.viewModel.process(viewAction: .cancel) + } +} + + +// MARK: - TemplateScreenViewModelViewDelegate +extension TemplateScreenViewController: TemplateScreenViewModelViewDelegate { + + func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didUpdateViewState viewSate: TemplateScreenViewState) { + self.render(viewState: viewSate) + } +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift new file mode 100644 index 000000000..9b716cddf --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModel.swift @@ -0,0 +1,85 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +final class TemplateScreenViewModel: TemplateScreenViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let session: MXSession + + // MARK: Public + + var message: String? + + weak var viewDelegate: TemplateScreenViewModelViewDelegate? + weak var coordinatorDelegate: TemplateScreenViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(session: MXSession) { + self.session = session + self.message = nil + } + + deinit { + } + + // MARK: - Public + + func process(viewAction: TemplateScreenViewAction) { + switch viewAction { + case .sayHello: + self.setupHelloMessage() + case .complete: + if let message = self.message { + self.coordinatorDelegate?.templateScreenViewModel(self, didCompleteWithMessage: message) + } + case .cancel: + self.coordinatorDelegate?.templateScreenViewModelDidCancel(self) + } + } + + // MARK: - Private + + private func setupHelloMessage() { + + self.update(viewState: .loading) + + // Check first that the user homeserver is federated with the Riot-bot homeserver + self.session.matrixRestClient.displayName(forUser: self.session.myUser.userId) { [weak self] (response) in + + guard let sself = self else { + return + } + + switch response { + case .success: + sself.message = "Hello \(response.value ?? "you")" + sself.update(viewState: .loaded) + case .failure(let error): + sself.update(viewState: .error(error)) + } + } + } + + private func update(viewState: TemplateScreenViewState) { + self.viewDelegate?.templateScreenViewModel(self, didUpdateViewState: viewState) + } +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift new file mode 100644 index 000000000..fd76d45b1 --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewModelType.swift @@ -0,0 +1,37 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +protocol TemplateScreenViewModelViewDelegate: class { + func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didUpdateViewState viewSate: TemplateScreenViewState) +} + +protocol TemplateScreenViewModelCoordinatorDelegate: class { + func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithMessage message: String) + func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType) +} + +/// Protocol describing the view model used by `TemplateScreenViewController` +protocol TemplateScreenViewModelType { + + var message: String? { get set } + + var viewDelegate: TemplateScreenViewModelViewDelegate? { get set } + var coordinatorDelegate: TemplateScreenViewModelCoordinatorDelegate? { get set } + + func process(viewAction: TemplateScreenViewAction) +} diff --git a/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift new file mode 100644 index 000000000..815fd8196 --- /dev/null +++ b/Tools/Templates/buildable/ScreenTemplate/TemplateScreenViewState.swift @@ -0,0 +1,24 @@ +/* + Copyright 2019 New Vector Ltd + + 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. + */ + +import Foundation + +/// TemplateScreenViewController view state +enum TemplateScreenViewState { + case loading + case loaded + case error(Error) +} diff --git a/Tools/Templates/createRootCoordinator.sh b/Tools/Templates/createRootCoordinator.sh new file mode 100755 index 000000000..f8d3deaa4 --- /dev/null +++ b/Tools/Templates/createRootCoordinator.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +if [ ! $# -eq 2 ] && [ ! $# -eq 3 ] ; then + echo "Usage: ./createRootCoordinator.sh Folder MyRootCoordinatorName [DefaultScreenName]" + exit 1 +fi + + +OUTPUT_DIR="../../Riot/Modules"/$1 +COORDINATOR_NAME=$2 +COORDINATOR_VAR_NAME=`echo $COORDINATOR_NAME | awk '{ print tolower(substr($0, 1, 1)) substr($0, 2) }'` +SCREEN_NAME=$3 +SCREEN_VAR_NAME=`echo $SCREEN_NAME | awk '{ print tolower(substr($0, 1, 1)) substr($0, 2) }'` + +MODULE_DIR="../../Riot/Modules" + +echo "Create folder ${OUTPUT_DIR}" + +mkdir -p $OUTPUT_DIR +cp -R buildable/FlowCoordinatorTemplate/ $OUTPUT_DIR/ + +cd $OUTPUT_DIR +for file in FlowTemplate* +do + if [ -f "$file" ]; then + echo "Building ${file/FlowTemplate/$COORDINATOR_NAME}..." + perl -p -i -e "s/FlowTemplate/"$COORDINATOR_NAME"/g" $file + perl -p -i -e "s/flowTemplate/"$COORDINATOR_VAR_NAME"/g" $file + + if [ -n "$SCREEN_NAME" ]; then + perl -p -i -e "s/TemplateScreen/"$SCREEN_NAME"/g" $file + perl -p -i -e "s/templateScreen/"$SCREEN_VAR_NAME"/g" $file + fi + + echo "// $ createRootCoordinator.sh $@" | cat - ${file} > /tmp/$$ && mv /tmp/$$ ${file} + echo '// File created from FlowTemplate' | cat - ${file} > /tmp/$$ && mv /tmp/$$ ${file} + + mv ${file} ${file/FlowTemplate/$COORDINATOR_NAME} + fi +done \ No newline at end of file diff --git a/Tools/Templates/createScreen.sh b/Tools/Templates/createScreen.sh new file mode 100755 index 000000000..3e3062f4b --- /dev/null +++ b/Tools/Templates/createScreen.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +if [ ! $# -eq 2 ]; then + echo "Usage: ./createScreen.sh Folder MyScreenName" + exit 1 +fi + +OUTPUT_DIR="../../Riot/Modules"/$1 +SCREEN_NAME=$2 +SCREEN_VAR_NAME=`echo $SCREEN_NAME | awk '{ print tolower(substr($0, 1, 1)) substr($0, 2) }'` + +MODULE_DIR="../../Riot/Modules" + +if [ -e $OUTPUT_DIR ]; then + echo "Error: Folder ${OUTPUT_DIR} already exists" + exit 1 +fi + +echo "Create folder ${OUTPUT_DIR}" + +mkdir -p $OUTPUT_DIR +cp -R buildable/ScreenTemplate/ $OUTPUT_DIR/ + +cd $OUTPUT_DIR +for file in * +do + echo "Building ${file/TemplateScreen/$SCREEN_NAME}..." + perl -p -i -e "s/TemplateScreen/"$SCREEN_NAME"/g" $file + perl -p -i -e "s/templateScreen/"$SCREEN_VAR_NAME"/g" $file + + if [[ ! $file == *.storyboard ]]; + then + echo "// $ createScreen.sh $@" | cat - ${file} > /tmp/$$ && mv /tmp/$$ ${file} + echo '// File created from ScreenTemplate' | cat - ${file} > /tmp/$$ && mv /tmp/$$ ${file} + fi + + mv ${file} ${file/TemplateScreen/$SCREEN_NAME} +done \ No newline at end of file