From 30bec8e9c705d76c63461c10f106932e8ccb9430 Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Thu, 13 Sep 2018 20:07:04 +0300 Subject: [PATCH] Add: NSNumberConvertible protocol for NumberFormattingService use cases. Add: TableDirector methods for rows insertion and removal without reload a whole table. Add: UIImageView binder for disclosure indicator rotation. Add: UIView.addSubviews(:) methods with variable number of arguments and array of views. Add: PlaceholderConfigurable that defines attributes and methods for view with placeholder and regular state. Add: ContentLoadingViewModel enum that describes possible PlaceholderConfigurable view states. --- CHANGELOG.md | 8 ++ LeadKit.podspec | 7 +- LeadKit.xcodeproj/project.pbxproj | 136 +++++++++++++++++- .../Enums/Views/ContentLoadingViewModel.swift | 32 +++++ .../Array/Array+RowExtensions.swift | 16 +-- ...ildInNumberTypes+NSNumberConvertible.swift | 71 +++++++++ ...mattingService+DefaultImplementation.swift | 40 +++--- .../TableDirector+Extensions.swift | 54 +++++++ ...UIImageView+ExpandCollapseDisclosure.swift | 49 +++++++ .../UIKit/UIView/UIView+AddSubviews.swift | 19 +++ .../ConfigurableView+Extensions.swift | 35 +++++ ...tializableView+DefaultImplementation.swift | 0 .../ContentLoadingViewModel+Extensions.swift | 55 +++++++ ...erConfigurable+DefaultImplementation.swift | 56 ++++++++ .../ViewBackground+Configuration.swift | 0 .../ViewTextConfigurable+Extensions.swift | 6 +- .../NSNumberConvertible.swift | 33 +++++ .../NumberFormattingService.swift | 57 ++------ .../PlaceholderConfigurable.swift | 56 ++++++++ 19 files changed, 642 insertions(+), 88 deletions(-) create mode 100644 Sources/Enums/Views/ContentLoadingViewModel.swift create mode 100644 Sources/Extensions/NumberFormattingService/BuildInNumberTypes+NSNumberConvertible.swift create mode 100644 Sources/Extensions/UIKit/UIImageView/UIImageView+ExpandCollapseDisclosure.swift create mode 100644 Sources/Extensions/UIKit/UIView/UIView+AddSubviews.swift create mode 100644 Sources/Extensions/Views/ConfigurableView/ConfigurableView+Extensions.swift rename Sources/Extensions/Views/{ => InitializableView}/InitializableView+DefaultImplementation.swift (100%) create mode 100644 Sources/Extensions/Views/PlaceholderConfigurable/ContentLoadingViewModel+Extensions.swift create mode 100644 Sources/Extensions/Views/PlaceholderConfigurable/PlaceholderConfigurable+DefaultImplementation.swift rename Sources/Extensions/Views/{ => ViewBackground}/ViewBackground+Configuration.swift (100%) create mode 100644 Sources/Protocols/NumberFormattingService/NSNumberConvertible.swift create mode 100644 Sources/Protocols/Views/PlaceholderConfigurable/PlaceholderConfigurable.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 01df7c7f..baffebe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### 0.8.10 +- **Add**: `NSNumberConvertible` protocol for `NumberFormattingService` use cases. +- **Add**: `TableDirector` methods for rows insertion and removal without reload a whole table. +- **Add**: `UIImageView` binder for disclosure indicator rotation. +- **Add**: `UIView.addSubviews(:)` methods with variable number of arguments and array of views. +- **Add**: `PlaceholderConfigurable` that defines attributes and methods for view with placeholder and regular state. +- **Add**: `ContentLoadingViewModel` enum that describes possible `PlaceholderConfigurable` view states. + ### 0.8.9 - **Add**: Methods `replace(with:)`, `asVoid()`, `asOptional()` to `ObservableType`, `SharedSequence` (aka `Driver`) and `Single`. - **Add**: `Completable.deferredJust(:)` static method. diff --git a/LeadKit.podspec b/LeadKit.podspec index d8bdd290..33079fae 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.8.9" + s.version = "0.8.10" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" @@ -49,13 +49,16 @@ Pod::Spec.new do |s| "Sources/Extensions/Array/Array+RowExtensions.swift", "Sources/Extensions/Drawing/UIImage/*", "Sources/Extensions/UIKit/**/*.swift", - "Sources/Extensions/Views/ViewBackground+Configuration.swift", + "Sources/Extensions/Views/ViewBackground/*", "Sources/Extensions/Views/SeparatorCell/*", + "Sources/Extensions/Views/ConfigurableView/*", + "Sources/Extensions/Views/PlaceholderConfigurable/*", "Sources/Protocols/UIKit/**/*.swift", "Sources/Protocols/LoadingIndicator.swift", "Sources/Protocols/DataLoading/PaginationDataLoading/PaginationWrappable.swift", "Sources/Protocols/DataLoading/GeneralDataLoading/GeneralDataLoadingController.swift", "Sources/Protocols/Views/SeparatorCell/*", + "Sources/Protocols/Views/PlaceholderConfigurable/*", "Sources/Protocols/TableKit/**/*", "Sources/Structures/Views/AnyLoadingIndicator.swift", "Sources/Structures/DrawingOperations/CALayerDrawingOperation.swift", diff --git a/LeadKit.xcodeproj/project.pbxproj b/LeadKit.xcodeproj/project.pbxproj index 77edc3f4..f261a0d6 100644 --- a/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit.xcodeproj/project.pbxproj @@ -403,6 +403,9 @@ 675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; 675E0AAA21072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; 675E0AAB21072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; }; + 6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; }; + 6760DC4E212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; }; + 6760DC4F212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; }; 6762131820A0BBA30034EEF1 /* TableSection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */; }; 676B22A2206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; 676B22A3206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */; }; @@ -511,6 +514,23 @@ 67955D53206D216B0021ECD2 /* Singleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67955D51206D216B0021ECD2 /* Singleton.swift */; }; 67955D54206D216B0021ECD2 /* Singleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67955D51206D216B0021ECD2 /* Singleton.swift */; }; 67955D55206D216B0021ECD2 /* Singleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67955D51206D216B0021ECD2 /* Singleton.swift */; }; + 67990AC5213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */; }; + 67990AC6213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */; }; + 67990AC7213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */; }; + 67990ACA213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */; }; + 67990ACB213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */; }; + 67990ACC213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */; }; + 67990ACD213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */; }; + 67990AD2213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */; }; + 67990AD3213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */; }; + 67990AD4213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */; }; + 67990AD6213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */; }; + 67990AD7213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */; }; + 67990AD8213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */; }; + 67990AD9213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */; }; + 67990AE6213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */; }; + 67990AE7213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */; }; + 67990AE8213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */; }; 67A1FF8F1EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; }; 67A1FF901EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; }; 67A1FF911EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */; }; @@ -558,6 +578,17 @@ 67E6C2361EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; 67E6C2371EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; 67E6C2381EBB32F5007842A6 /* SingleLoadCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */; }; + 67E9024B2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */; }; + 67E9024C2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */; }; + 67E9024D2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */; }; + 67E9024E2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */; }; + 67E902512125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */; }; + 67E902522125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */; }; + 67E902532125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */; }; + 67E902542125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */; }; + 67E902572125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */; }; + 67E902582125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */; }; + 67E902592125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */; }; 67EB7FC0206140E600BDD9FB /* TotalCountCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */; }; 67EB7FC1206140E600BDD9FB /* TotalCountCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */; }; 67EB7FC2206140E600BDD9FB /* TotalCountCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */; }; @@ -849,6 +880,7 @@ 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseConfigurableController.swift; sourceTree = ""; }; 674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = ""; }; 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseScrollContentController.swift; sourceTree = ""; }; + 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+AddSubviews.swift"; sourceTree = ""; }; 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = ""; }; 676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = ""; }; 67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = ""; }; @@ -889,6 +921,11 @@ 67952DDC1EB3280900B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = ""; }; 67952DDE1EB3285A00B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = ""; }; 67955D51206D216B0021ECD2 /* Singleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Singleton.swift; sourceTree = ""; }; + 67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderConfigurable.swift; sourceTree = ""; }; + 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLoadingViewModel.swift; sourceTree = ""; }; + 67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlaceholderConfigurable+DefaultImplementation.swift"; sourceTree = ""; }; + 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContentLoadingViewModel+Extensions.swift"; sourceTree = ""; }; + 67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurableView+Extensions.swift"; sourceTree = ""; }; 679C77D41F98F78E0094BE10 /* AlertRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertRepresentable.swift; sourceTree = ""; }; 679C77D61F98F7A60094BE10 /* UIAlertController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extensions.swift"; sourceTree = ""; }; 67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Spinner.swift"; sourceTree = ""; }; @@ -905,6 +942,9 @@ 67E352562119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewTextConfigurable+Extensions.swift"; sourceTree = ""; }; 67E3525E2119B7570035BDDB /* BasePlaceholerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasePlaceholerView.swift; sourceTree = ""; }; 67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLoadCursor.swift; sourceTree = ""; }; + 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNumberConvertible.swift; sourceTree = ""; }; + 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BuildInNumberTypes+NSNumberConvertible.swift"; sourceTree = ""; }; + 67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+ExpandCollapseDisclosure.swift"; sourceTree = ""; }; 67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursor.swift; sourceTree = ""; }; 67EB7FC6206148D000BDD9FB /* TotalCountCursorListingResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorListingResult.swift; sourceTree = ""; }; 67EB7FCE20615B8900BDD9FB /* TotalCountCursorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorConfiguration.swift; sourceTree = ""; }; @@ -1262,11 +1302,12 @@ 671462111EB3396E00EAB194 /* UIView */ = { isa = PBXGroup; children = ( - 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */, + 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */, EFBE57DA1EC361620040E00A /* UIView+Layout.swift */, 671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */, 671462151EB3396E00EAB194 /* UIView+LoadingIndicator.swift */, 671462161EB3396E00EAB194 /* UIView+Rotation.swift */, + 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */, ); path = UIView; sourceTree = ""; @@ -1467,6 +1508,7 @@ children = ( 67274768206CCC9D00725163 /* ViewBackground.swift */, 67274771206CCF1200725163 /* ViewText.swift */, + 67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */, ); path = Views; sourceTree = ""; @@ -1474,10 +1516,12 @@ 6727476C206CCD3100725163 /* Views */ = { isa = PBXGroup; children = ( - 67E352552119AC770035BDDB /* ViewText */, + 67990AE0213EB3C90040D195 /* ConfigurableView */, + 67990ACF213EA6460040D195 /* InitializableView */, + 67990ACE213EA62A0040D195 /* PlaceholderConfigurable */, 6792623A206EB0D800308E62 /* SeparatorCell */, - 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */, - 6727476D206CCDDB00725163 /* ViewBackground+Configuration.swift */, + 67990AD0213EA6530040D195 /* ViewBackground */, + 67E352552119AC770035BDDB /* ViewText */, ); path = Views; sourceTree = ""; @@ -1509,6 +1553,7 @@ 671AD260206A35C500EAF887 /* UIApplication */, 67E3525C2119B4AD0035BDDB /* UIButton */, 672947E4206EA67B00AC6B6B /* UIImage */, + 67E902552125B55E008EDF45 /* UIImageView */, 67274776206CD07B00725163 /* UILabel */, 6741CEB820E242CF00FEC4D9 /* UIScrollView */, 36DAAF4F2007CC330090BE0D /* UITableView */, @@ -1550,6 +1595,7 @@ 673564EF2068C29100F0CBED /* NumberFormattingService */ = { isa = PBXGroup; children = ( + 67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */, 673564F02068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift */, ); path = NumberFormattingService; @@ -1857,6 +1903,7 @@ 678D269C20692BFF00B05B93 /* Views */ = { isa = PBXGroup; children = ( + 67990AC3213EA4BD0040D195 /* PlaceholderConfigurable */, 677B06BC2118753F006C947D /* InitializableView */, 67926234206EB08400308E62 /* SeparatorCell */, 678D269D20692BFF00B05B93 /* TextField */, @@ -1891,6 +1938,47 @@ path = SeparatorCell; sourceTree = ""; }; + 67990AC3213EA4BD0040D195 /* PlaceholderConfigurable */ = { + isa = PBXGroup; + children = ( + 67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */, + ); + path = PlaceholderConfigurable; + sourceTree = ""; + }; + 67990ACE213EA62A0040D195 /* PlaceholderConfigurable */ = { + isa = PBXGroup; + children = ( + 67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */, + 67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */, + ); + path = PlaceholderConfigurable; + sourceTree = ""; + }; + 67990ACF213EA6460040D195 /* InitializableView */ = { + isa = PBXGroup; + children = ( + 67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */, + ); + path = InitializableView; + sourceTree = ""; + }; + 67990AD0213EA6530040D195 /* ViewBackground */ = { + isa = PBXGroup; + children = ( + 6727476D206CCDDB00725163 /* ViewBackground+Configuration.swift */, + ); + path = ViewBackground; + sourceTree = ""; + }; + 67990AE0213EB3C90040D195 /* ConfigurableView */ = { + isa = PBXGroup; + children = ( + 67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */, + ); + path = ConfigurableView; + sourceTree = ""; + }; 679C77D51F98F7A60094BE10 /* UIAlertController */ = { isa = PBXGroup; children = ( @@ -1910,6 +1998,7 @@ 67C7B1772068BADA00C9EDA3 /* NumberFormattingService */ = { isa = PBXGroup; children = ( + 67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */, 673564F52068C68D00F0CBED /* NumberFormat.swift */, 67C7B1782068BB1C00C9EDA3 /* NumberFormattingService.swift */, ); @@ -1965,6 +2054,14 @@ path = UIButton; sourceTree = ""; }; + 67E902552125B55E008EDF45 /* UIImageView */ = { + isa = PBXGroup; + children = ( + 67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */, + ); + path = UIImageView; + sourceTree = ""; + }; 67EB7FC5206148C400BDD9FB /* DataLoading */ = { isa = PBXGroup; children = ( @@ -2850,6 +2947,7 @@ 678D26A420692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */, 671462801EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */, 67EB7FF8206175F700BDD9FB /* PaginationWrappable.swift in Sources */, + 67990AD6213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */, 671463541EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */, 673CF4112063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */, 673CF42C2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */, @@ -2864,6 +2962,7 @@ 6741CEAF20E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */, 67CAF8C620652E2A00527085 /* TextFieldViewModel.swift in Sources */, 671462681EB3396E00EAB194 /* NetworkService.swift in Sources */, + 67990ACA213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */, 671463101EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 67386A8C206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, 674AF55C1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift in Sources */, @@ -2891,6 +2990,7 @@ 671463301EB3396E00EAB194 /* CursorType.swift in Sources */, 67FDC25F1FA310EA00C76A77 /* RequestError.swift in Sources */, 677B06A021186A69006C947D /* SharedSequence+Extensions.swift in Sources */, + 6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */, 67745268206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */, 6714624C1EB3396E00EAB194 /* MapCursor.swift in Sources */, A6C9A4FA1F8BBCF2009311CC /* EmptyCell.swift in Sources */, @@ -2911,8 +3011,11 @@ 6714627C1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */, 67E352572119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift in Sources */, + 67990AC5213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */, 6741CEBE20E242FA00FEC4D9 /* UIScrollView+RxBindings.swift in Sources */, + 67E902572125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */, 671462781EB3396E00EAB194 /* ResizeMode.swift in Sources */, + 67E902512125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */, A676AE551F98112E001F9214 /* ObservableMappable.swift in Sources */, 6741CEA520E2418200FEC4D9 /* TableViewHolder.swift in Sources */, A6E0DDE11F8A696F002CA74E /* SeparatorRowBox.swift in Sources */, @@ -2933,6 +3036,7 @@ 6713C24120AF189100875921 /* RxNetworkOperationModel.swift in Sources */, 677452AE206274630024EEEF /* PaginationWrapper.swift in Sources */, 6741CEC220E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */, + 67990AD2213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */, A6E0DDF11F8A6C80002CA74E /* SeparatorConfiguration.swift in Sources */, 6727477F206CD3BD00725163 /* ViewText+Extensions.swift in Sources */, 67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, @@ -2940,6 +3044,7 @@ 673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */, B85B768720B1CF6700F837C4 /* Encodable+Extensions.swift in Sources */, 671AD267206A365100EAF887 /* UIApplication+OpenUrlSupport.swift in Sources */, + 67E9024B2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */, 673CF40B2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */, 6713C23720AF0C4D00875921 /* NetworkOperationState.swift in Sources */, 6714636C1EB3396E00EAB194 /* XibNameProtocol.swift in Sources */, @@ -3004,6 +3109,7 @@ 677452A9206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */, 677B06B221186C14006C947D /* Completable+DeferredJust.swift in Sources */, 671462501EB3396E00EAB194 /* StaticCursor.swift in Sources */, + 67990AE6213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */, 6741C40F20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */, 67EB7FC7206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */, 67745286206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */, @@ -3086,6 +3192,7 @@ EF24213C2076D5C900FA9BE6 /* NetworkServiceConfiguration.swift in Sources */, 6774528F20625C9E0024EEEF /* GeneralDataLoadingState.swift in Sources */, 671463261EB3396E00EAB194 /* Any+TypeName.swift in Sources */, + 67E9024D2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */, 6714638A1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, 67153E3C207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */, 6774529C20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, @@ -3123,7 +3230,9 @@ 67EB7FED2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 6714637E1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, 671463361EB3396E00EAB194 /* DrawingOperation.swift in Sources */, + 67990ACC213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */, 676B22A4206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */, + 67990AD8213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */, 671462721EB3396E00EAB194 /* CursorError.swift in Sources */, 677B06AD21186BB6006C947D /* Single+Extensions.swift in Sources */, 67386A8E206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */, @@ -3156,6 +3265,7 @@ 6714629E1EB3396E00EAB194 /* CursorType+Slice.swift in Sources */, 6714636A1EB3396E00EAB194 /* ConfigurableView.swift in Sources */, B84CB07A20B872AD0090DB91 /* Decodable+Extensions.swift in Sources */, + 67E902532125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3166,6 +3276,7 @@ 6714634B1EB3396E00EAB194 /* ResettableType.swift in Sources */, 671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */, 67ED2BE120B44DEB00508B3E /* InitializableView.swift in Sources */, + 67990AD9213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */, 67274775206CCF1200725163 /* ViewText.swift in Sources */, 6727476B206CCCA500725163 /* ViewBackground.swift in Sources */, 6741C41220EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */, @@ -3211,10 +3322,12 @@ 671AD26F206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */, 67955D55206D216B0021ECD2 /* Singleton.swift in Sources */, EFBE57D31EC35EF20040E00A /* Array+Extensions.swift in Sources */, + 67990AD4213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */, 36FE777320F669E300284C09 /* String+ConvertToHost.swift in Sources */, 67FD4385206BD24B005B0C64 /* EqutableOptionalArray.swift in Sources */, 67CAF8AE2065189C00527085 /* NetworkService+ActivityIndicator.swift in Sources */, 6714638B1EB3396E00EAB194 /* RoundDrawingOperation.swift in Sources */, + 67990AC7213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */, 67EB7FFF206176C900BDD9FB /* AnyPaginationWrappable.swift in Sources */, A676AE4A1F97D28A001F9214 /* String+Extensions.swift in Sources */, 671463831EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */, @@ -3230,6 +3343,7 @@ 671462AF1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, A676AE4F1F9810C1001F9214 /* Any+Cast.swift in Sources */, 6741CEC420E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */, + 67E9024E2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */, 671463031EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, 6714627F1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 677B06AE21186BB6006C947D /* Single+Extensions.swift in Sources */, @@ -3276,6 +3390,7 @@ 677B06B521186C14006C947D /* Completable+DeferredJust.swift in Sources */, 6727478D206CD83600725163 /* DateFormat.swift in Sources */, 67EB7FDD20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */, + 67990AE8213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */, 677452A720625FA90024EEEF /* RxDataSource.swift in Sources */, 6741CEBC20E242D900FEC4D9 /* UIScrollView+ScrollViewHolder.swift in Sources */, 6774527720624E820024EEEF /* DataLoadingModel.swift in Sources */, @@ -3289,6 +3404,7 @@ 671462971EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */, 671463671EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */, 67A1FF911EBCA09B00D6C89F /* UIImage+Spinner.swift in Sources */, + 67E902542125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */, 6714624B1EB3396E00EAB194 /* FixedPageCursor.swift in Sources */, 671462CB1EB3396E00EAB194 /* String+Localization.swift in Sources */, 6741CEAB20E2418B00FEC4D9 /* CollectionViewHolder.swift in Sources */, @@ -3296,17 +3412,20 @@ 671462BB1EB3396E00EAB194 /* Sequence+ConcurrentMap.swift in Sources */, 67EB7FEE2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */, 671463771EB3396E00EAB194 /* BorderDrawingOperation.swift in Sources */, + 6760DC4F212F351700020BAE /* UIView+AddSubviews.swift in Sources */, 6714633F1EB3396E00EAB194 /* LoadingIndicator.swift in Sources */, 675C1FB41F97CA32007D5249 /* AppearanceConfigurable.swift in Sources */, 6714631B1EB3396E00EAB194 /* UIWindow+Extensions.swift in Sources */, 673CF4252063D90600C329F6 /* DisposeBagHolder.swift in Sources */, 6714637B1EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */, + 67E902592125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */, 6741CEA720E2418200FEC4D9 /* TableViewHolder.swift in Sources */, 67DB776B21087154001CB56B /* CollectionViewWrapperView.swift in Sources */, 6774529520625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */, 6713C23A20AF0C4D00875921 /* NetworkOperationState.swift in Sources */, 6774529D20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */, 6714632F1EB3396E00EAB194 /* ConfigurableController.swift in Sources */, + 67990ACD213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */, 67EB7FF42061682F00BDD9FB /* TotalCountCursorListingResult+DefaultTotalCountCursorListingResult.swift in Sources */, 6714628F1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */, 67051ADD1EBC7C36008EADC0 /* SpinnerView.swift in Sources */, @@ -3385,7 +3504,10 @@ 671462691EB3396E00EAB194 /* NetworkService.swift in Sources */, 671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */, 67153E41207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */, + 67990AE7213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */, 671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */, + 6760DC4E212F351700020BAE /* UIView+AddSubviews.swift in Sources */, + 67E902582125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */, 673564F72068C68D00F0CBED /* NumberFormat.swift in Sources */, 67E352582119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift in Sources */, 67051ADC1EBC7C36008EADC0 /* SpinnerView.swift in Sources */, @@ -3422,7 +3544,9 @@ 671463291EB3396E00EAB194 /* BaseViewModel.swift in Sources */, 671462AD1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */, 671463011EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */, + 67990AC6213EA4DB0040D195 /* PlaceholderConfigurable.swift in Sources */, 6774526D206249E30024EEEF /* UICollectionView+PaginationWrappable.swift in Sources */, + 67990AD7213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */, 6714627D1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */, 673CF4352063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */, 675E0AAA21072FF400CDC143 /* BaseScrollContentController.swift in Sources */, @@ -3447,6 +3571,7 @@ 67ED2BDF20B44DEB00508B3E /* InitializableView.swift in Sources */, 6714626D1EB3396E00EAB194 /* XibView.swift in Sources */, 6714637D1EB3396E00EAB194 /* ImageDrawingOperation.swift in Sources */, + 67E902522125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */, 671463351EB3396E00EAB194 /* DrawingOperation.swift in Sources */, 6741CED220E243F800FEC4D9 /* BaseConfigurableController.swift in Sources */, 677452A020625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */, @@ -3468,6 +3593,7 @@ 67274790206CD88600725163 /* DateFormattingService.swift in Sources */, 67955D53206D216B0021ECD2 /* Singleton.swift in Sources */, A676AE4E1F9810C1001F9214 /* Any+Cast.swift in Sources */, + 67990AD3213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift in Sources */, 671462951EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */, 67EB7FF22061682F00BDD9FB /* TotalCountCursorListingResult+DefaultTotalCountCursorListingResult.swift in Sources */, 671463651EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */, @@ -3509,6 +3635,7 @@ 67274779206CD0B500725163 /* UILabel+ViewTextConfigurable.swift in Sources */, 67EB7FC8206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */, 671462751EB3396E00EAB194 /* LeadKitError.swift in Sources */, + 67990ACB213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */, EFBE57D11EC35EF20040E00A /* Array+Extensions.swift in Sources */, 676B22A3206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */, 671462D91EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */, @@ -3523,6 +3650,7 @@ 671463691EB3396E00EAB194 /* ConfigurableView.swift in Sources */, 67EB7FD020615B8900BDD9FB /* TotalCountCursorConfiguration.swift in Sources */, 67CAF8AC2065189C00527085 /* NetworkService+ActivityIndicator.swift in Sources */, + 67E9024C2125AEB4008EDF45 /* NSNumberConvertible.swift in Sources */, 6B5B6F4E2B4F6F74348AC138 /* TableKitViewModel.swift in Sources */, 6B5B6481B4160AE6D0205CD6 /* TableKitViewModel+Extenstions.swift in Sources */, 677B06A121186A69006C947D /* SharedSequence+Extensions.swift in Sources */, diff --git a/Sources/Enums/Views/ContentLoadingViewModel.swift b/Sources/Enums/Views/ContentLoadingViewModel.swift new file mode 100644 index 00000000..03e2bfcd --- /dev/null +++ b/Sources/Enums/Views/ContentLoadingViewModel.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/// Enum that describes possible PlaceholderConfigurable view states. +/// +/// - placeholder: Placeholder state with placeholder view model. +/// - content: Content state with content view model. +public enum ContentLoadingViewModel { + + case placeholder(PlaceholderType) + case content(ContentType) + +} diff --git a/Sources/Extensions/Array/Array+RowExtensions.swift b/Sources/Extensions/Array/Array+RowExtensions.swift index a971da2c..9478bd13 100644 --- a/Sources/Extensions/Array/Array+RowExtensions.swift +++ b/Sources/Extensions/Array/Array+RowExtensions.swift @@ -22,20 +22,16 @@ import TableKit -public extension Array where Element: Row { - - /// Creates TableSection with empty, zero height header and footer. - var onlyRowsSection: TableSection { - return TableSection(onlyRows: self) - } - -} - public extension Array where Element: TableKitViewModel { + /// Creates [Row] array from TableKitViewModels. + var tableRows: [Row] { + return map { $0.tableRow } + } + /// Creates TableSection with empty, zero height header and footer. var onlyRowsSection: TableSection { - return map { $0.tableRow }.onlyRowsSection + return TableSection(onlyRows: tableRows) } } diff --git a/Sources/Extensions/NumberFormattingService/BuildInNumberTypes+NSNumberConvertible.swift b/Sources/Extensions/NumberFormattingService/BuildInNumberTypes+NSNumberConvertible.swift new file mode 100644 index 00000000..e351c70d --- /dev/null +++ b/Sources/Extensions/NumberFormattingService/BuildInNumberTypes+NSNumberConvertible.swift @@ -0,0 +1,71 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +extension NSNumber: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return self + } + +} + +extension Decimal: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return NSDecimalNumber(decimal: self) + } + +} + +extension Int: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return NSNumber(value: self) + } + +} + +extension Int64: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return NSNumber(value: self) + } + +} + +extension Double: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return NSNumber(value: self) + } + +} + +extension Float: NSNumberConvertible { + + public func asNSNumber() -> NSNumber { + return NSNumber(value: self) + } + +} diff --git a/Sources/Extensions/NumberFormattingService/NumberFormattingService+DefaultImplementation.swift b/Sources/Extensions/NumberFormattingService/NumberFormattingService+DefaultImplementation.swift index b4e6c8ab..c27fa1ec 100644 --- a/Sources/Extensions/NumberFormattingService/NumberFormattingService+DefaultImplementation.swift +++ b/Sources/Extensions/NumberFormattingService/NumberFormattingService+DefaultImplementation.swift @@ -25,11 +25,11 @@ import Foundation public extension NumberFormattingService { /// Computed static property. Use only once for `formatters` field implementation! - static var computedFormatters: [NumberFormatType: NumberFormatter] { + var computedFormatters: [NumberFormatType: NumberFormatter] { return Dictionary(uniqueKeysWithValues: NumberFormatType.allOptions.map { ($0, $0.numberFormatter) }) } - static func numberFormatter(for format: NumberFormatType) -> NumberFormatter { + func numberFormatter(for format: NumberFormatType) -> NumberFormatter { guard let formatter = formatters[format] else { fatalError("Unregistered number formatter for \(format)") } @@ -37,28 +37,24 @@ public extension NumberFormattingService { return formatter } - static func string(from number: NSNumber, format: NumberFormatType, defaultString: String = "") -> String { - return numberFormatter(for: format).string(from: number) ?? defaultString + func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String { + return numberFormatter(for: format).string(from: number.asNSNumber()) ?? defaultString } - static func string(from number: Decimal, format: NumberFormatType, defaultString: String = "") -> String { - return string(from: NSDecimalNumber(decimal: number), format: format, defaultString: defaultString) - } - - static func string(from number: Int, format: NumberFormatType, defaultString: String = "") -> String { - return string(from: NSNumber(value: number), format: format, defaultString: defaultString) - } - - static func string(from number: Int64, format: NumberFormatType, defaultString: String = "") -> String { - return string(from: NSNumber(value: number), format: format, defaultString: defaultString) - } - - static func string(from number: Float, format: NumberFormatType, defaultString: String = "") -> String { - return string(from: NSNumber(value: Double(number)), format: format, defaultString: defaultString) - } - - static func string(from number: Double, format: NumberFormatType, defaultString: String = "") -> String { - return string(from: NSNumber(value: number), format: format, defaultString: defaultString) + func number(from string: String, format: NumberFormatType) -> NSNumber? { + return numberFormatter(for: format).number(from: string) + } + +} + +public extension NumberFormattingService where Self: Singleton { + + static func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String { + return shared.string(from: number, format: format, defaultString: defaultString) + } + + static func number(from string: String, format: NumberFormatType) -> NSNumber? { + return shared.number(from: string, format: format) } } diff --git a/Sources/Extensions/TableKit/TableDirector/TableDirector+Extensions.swift b/Sources/Extensions/TableKit/TableDirector/TableDirector+Extensions.swift index 51ae36c8..0f810c79 100644 --- a/Sources/Extensions/TableKit/TableDirector/TableDirector+Extensions.swift +++ b/Sources/Extensions/TableKit/TableDirector/TableDirector+Extensions.swift @@ -116,4 +116,58 @@ public extension TableDirector { clear().append(section: TableSection(onlyRows: [])).reload() } + /// Inserts rows into table without complete reload. + /// + /// - Parameters: + /// - rows: Rows to insert. + /// - indexPath: Position of first row. + /// - animation: The type of animation when rows are inserted + /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside. + func insert(rows: [Row], + at indexPath: IndexPath, + with animation: UITableViewRowAnimation, + manualBeginEndUpdates: Bool = false) { + sections[indexPath.section].insert(rows: rows, at: indexPath.row) + let indexPaths: [IndexPath] = rows.indices.map { + IndexPath(row: indexPath.row + $0, section: indexPath.section) + } + + if manualBeginEndUpdates { + tableView?.insertRows(at: indexPaths, with: animation) + } else { + tableView?.beginUpdates() + tableView?.insertRows(at: indexPaths, with: animation) + tableView?.endUpdates() + } + } + + /// Removes rows from table without complete reload. + /// + /// - Parameters: + /// - rowsCount: Number of rows to remove. + /// - indexPath: Position of first row to remove. + /// - animation: The type of animation when rows are deleted + /// - manualBeginEndUpdates: Don't call beginUpdates() & endUpdates() inside. + func remove(rowsCount: Int, + startingAt indexPath: IndexPath, + with animation: UITableViewRowAnimation, + manualBeginEndUpdates: Bool = false) { + var indexPaths = [IndexPath]() + for index in indexPath.row ..< indexPath.row + rowsCount { + indexPaths.append(IndexPath(row: index, section: indexPath.section)) + } + + indexPaths.reversed().forEach { + sections[$0.section].remove(rowAt: $0.row) + } + + if manualBeginEndUpdates { + tableView?.deleteRows(at: indexPaths, with: animation) + } else { + tableView?.beginUpdates() + tableView?.deleteRows(at: indexPaths, with: animation) + tableView?.endUpdates() + } + } + } diff --git a/Sources/Extensions/UIKit/UIImageView/UIImageView+ExpandCollapseDisclosure.swift b/Sources/Extensions/UIKit/UIImageView/UIImageView+ExpandCollapseDisclosure.swift new file mode 100644 index 00000000..39261f93 --- /dev/null +++ b/Sources/Extensions/UIKit/UIImageView/UIImageView+ExpandCollapseDisclosure.swift @@ -0,0 +1,49 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import RxCocoa + +private extension Double { + static let halfPeriod = 0.5 +} + +public extension UIImageView { + + /// Rotates image view by 180 degrees via transform property with animation. + var expandRotationBinder: Binder { + return Binder(self) { view, isExpanded in + + let angle = isExpanded ? CGFloat.pi / 2 : -CGFloat.pi / 2 + + UIView.animateKeyframes(withDuration: CATransaction.animationDuration(), delay: 0, options: [], animations: { + UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: .halfPeriod, animations: { + view.transform = view.transform.rotated(by: angle) + }) + + UIView.addKeyframe(withRelativeStartTime: .halfPeriod, relativeDuration: .halfPeriod, animations: { + view.transform = view.transform.rotated(by: angle) + }) + }) + } + } + +} diff --git a/Sources/Extensions/UIKit/UIView/UIView+AddSubviews.swift b/Sources/Extensions/UIKit/UIView/UIView+AddSubviews.swift new file mode 100644 index 00000000..b6d8dc08 --- /dev/null +++ b/Sources/Extensions/UIKit/UIView/UIView+AddSubviews.swift @@ -0,0 +1,19 @@ +import UIKit.UIView + +public extension UIView { + + /// Adds views to current view. + /// + /// - Parameter views: Views tha will be added to view. + func addSubviews(_ views: UIView...) { + views.forEach { addSubview($0) } + } + + /// Adds views to current view. + /// + /// - Parameter views: Views tha will be added to view. + func addSubviews(_ views: [UIView]) { + views.forEach { addSubview($0) } + } + +} diff --git a/Sources/Extensions/Views/ConfigurableView/ConfigurableView+Extensions.swift b/Sources/Extensions/Views/ConfigurableView/ConfigurableView+Extensions.swift new file mode 100644 index 00000000..e2d94f02 --- /dev/null +++ b/Sources/Extensions/Views/ConfigurableView/ConfigurableView+Extensions.swift @@ -0,0 +1,35 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit.UIView + +public extension ConfigurableView where Self: UIView { + + /// Convenience initializer for configurable UIView subclass. + /// + /// - Parameter viewModel: View model to configure view after initialization. + init(viewModel: ViewModelType) { + self.init() + self.configure(with: viewModel) + } + +} diff --git a/Sources/Extensions/Views/InitializableView+DefaultImplementation.swift b/Sources/Extensions/Views/InitializableView/InitializableView+DefaultImplementation.swift similarity index 100% rename from Sources/Extensions/Views/InitializableView+DefaultImplementation.swift rename to Sources/Extensions/Views/InitializableView/InitializableView+DefaultImplementation.swift diff --git a/Sources/Extensions/Views/PlaceholderConfigurable/ContentLoadingViewModel+Extensions.swift b/Sources/Extensions/Views/PlaceholderConfigurable/ContentLoadingViewModel+Extensions.swift new file mode 100644 index 00000000..e644f3b3 --- /dev/null +++ b/Sources/Extensions/Views/PlaceholderConfigurable/ContentLoadingViewModel+Extensions.swift @@ -0,0 +1,55 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public extension ContentLoadingViewModel { + + /// Returns true if self == .placeholder. + var isPlaceholder: Bool { + if case .placeholder = self { + return true + } else { + return false + } + } + +} + +public extension ContentLoadingViewModel where PlaceholderType == Void { + + /// Creates ContentLoadingViewModel with placeholder. + static var placeholder: ContentLoadingViewModel { + return .placeholder(()) + } + +} + +public extension ContentLoadingViewModel where PlaceholderType == [Void] { + + /// Creates ContentLoadingViewModel with placeholder. + /// + /// - Parameter numberOfItems: Number of placeholders to create. + /// - Returns: ContentLoadingViewModel with placeholder. + static func placeholders(numberOfItems: Int) -> ContentLoadingViewModel { + return .placeholder(Array(repeating: (), count: numberOfItems)) + } + +} diff --git a/Sources/Extensions/Views/PlaceholderConfigurable/PlaceholderConfigurable+DefaultImplementation.swift b/Sources/Extensions/Views/PlaceholderConfigurable/PlaceholderConfigurable+DefaultImplementation.swift new file mode 100644 index 00000000..9585583e --- /dev/null +++ b/Sources/Extensions/Views/PlaceholderConfigurable/PlaceholderConfigurable+DefaultImplementation.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public extension PlaceholderConfigurable { + + func configureContentLoading(with contentLoadingViewModel: ContentLoadingViewModelType) { + switch contentLoadingViewModel { + case .content(let contentViewModel): + configure(contentViewModel: contentViewModel) + case .placeholder(let placeholderViewModel): + configure(placeholderViewModel: placeholderViewModel) + } + + setPlaceholder(visible: contentLoadingViewModel.isPlaceholder) + } + + func configure(placeholderViewModel: PlaceholderViewModelType) { + // typically nothing + } + + /// Shows or hides placeholder. + /// + /// - Parameter visible: A Boolean value that determines whether the placeholder content is visible. + func setPlaceholder(visible: Bool) { + contentContainerView.isHidden = visible + placeholderContainerView.isHidden = !visible + } + + /// Creates content view model for this type. + /// + /// - Parameter contentViewModel: Content of ContentLoadingViewModel. + /// - Returns: ContentLoadingViewModel with content. + static func content(with contentViewModel: ContentViewModelType) -> ContentLoadingViewModelType { + return .content(contentViewModel) + } + +} diff --git a/Sources/Extensions/Views/ViewBackground+Configuration.swift b/Sources/Extensions/Views/ViewBackground/ViewBackground+Configuration.swift similarity index 100% rename from Sources/Extensions/Views/ViewBackground+Configuration.swift rename to Sources/Extensions/Views/ViewBackground/ViewBackground+Configuration.swift diff --git a/Sources/Extensions/Views/ViewText/ViewTextConfigurable+Extensions.swift b/Sources/Extensions/Views/ViewText/ViewTextConfigurable+Extensions.swift index 469a3880..a0cb75e4 100644 --- a/Sources/Extensions/Views/ViewText/ViewTextConfigurable+Extensions.swift +++ b/Sources/Extensions/Views/ViewText/ViewTextConfigurable+Extensions.swift @@ -29,7 +29,7 @@ public extension ViewTextConfigurable { switch viewText { case .string(let text, let textAttributes): self.text = text - self.configureBaseArrearance(with: textAttributes) + self.configureBaseAppearance(with: textAttributes) case .attributedString(let attributedString): self.attributedText = attributedString } @@ -38,7 +38,7 @@ public extension ViewTextConfigurable { /// Configures text appearance of view. /// /// - Parameter baseTextAttributes: Set of attributes to configure appearance of text. - func configureBaseArrearance(with baseTextAttributes: BaseTextAttributes) { + func configureBaseAppearance(with baseTextAttributes: BaseTextAttributes) { textFont = baseTextAttributes.font titleColor = baseTextAttributes.color textAlignment = baseTextAttributes.alignment @@ -52,7 +52,7 @@ public extension BaseTextAttributes { /// /// - Parameter view: ViewTextConfigurable instance to configure with BaseTextAttributes. func configureBaseApperance(of view: ViewTextConfigurable) { - view.configureBaseArrearance(with: self) + view.configureBaseAppearance(with: self) } } diff --git a/Sources/Protocols/NumberFormattingService/NSNumberConvertible.swift b/Sources/Protocols/NumberFormattingService/NSNumberConvertible.swift new file mode 100644 index 00000000..ee13c25b --- /dev/null +++ b/Sources/Protocols/NumberFormattingService/NSNumberConvertible.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Protocol describes type that can be converted to NSNumber. +public protocol NSNumberConvertible { + + /// Convert value to NSNumber. + /// + /// - Returns: A value, expressed as an NSNumber. + func asNSNumber() -> NSNumber + +} diff --git a/Sources/Protocols/NumberFormattingService/NumberFormattingService.swift b/Sources/Protocols/NumberFormattingService/NumberFormattingService.swift index 5e54c76c..14317f88 100644 --- a/Sources/Protocols/NumberFormattingService/NumberFormattingService.swift +++ b/Sources/Protocols/NumberFormattingService/NumberFormattingService.swift @@ -27,66 +27,29 @@ public protocol NumberFormattingService { associatedtype NumberFormatType: NumberFormat - static var formatters: [NumberFormatType: NumberFormatter] { get } + var formatters: [NumberFormatType: NumberFormatter] { get } - /// Method returns NumberFormatter for given NumberFormatType. + /// Returns NumberFormatter for given NumberFormatType. /// /// - Parameter format: A number format under which should be configured NumberFormatter. /// - Returns: Configured NumberFormatter instance. - static func numberFormatter(for format: NumberFormatType) -> NumberFormatter + func numberFormatter(for format: NumberFormatType) -> NumberFormatter - /// Method format number in given format. If formatting fails - it returns default string. + /// Format number in given format. If formatting fails - it returns default string. /// /// - Parameters: /// - number: A number to format. /// - format: A format that should be used for number formatting. /// - defaultString: Default string if formatting will fail. /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: NSNumber, format: NumberFormatType, defaultString: String) -> String + func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String) -> String - /// Method format number in given format. If formatting fails - it returns default string. + /// Parses number from string in given format. /// /// - Parameters: - /// - number: A number to format. - /// - format: A format that should be used for number formatting. - /// - defaultString: Default string if formatting will fail. - /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: Int, format: NumberFormatType, defaultString: String) -> String - - /// Method format number in given format. If formatting fails - it returns default string. - /// - /// - Parameters: - /// - number: A number to format. - /// - format: A format that should be used for number formatting. - /// - defaultString: Default string if formatting will fail. - /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: Int64, format: NumberFormatType, defaultString: String) -> String - - /// Method format number in given format. If formatting fails - it returns default string. - /// - /// - Parameters: - /// - number: A number to format. - /// - format: A format that should be used for number formatting. - /// - defaultString: Default string if formatting will fail. - /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: Float, format: NumberFormatType, defaultString: String) -> String - - /// Method format number in given format. If formatting fails - it returns default string. - /// - /// - Parameters: - /// - number: A number to format. - /// - format: A format that should be used for number formatting. - /// - defaultString: Default string if formatting will fail. - /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: Double, format: NumberFormatType, defaultString: String) -> String - - /// Method format number in given format. If formatting fails - it returns default string. - /// - /// - Parameters: - /// - number: A number to format. - /// - format: A format that should be used for number formatting. - /// - defaultString: Default string if formatting will fail. - /// - Returns: An string that contains formatted number or default string if formatting did fail. - static func string(from number: Decimal, format: NumberFormatType, defaultString: String) -> String + /// - string: A string to parse. + /// - format: A format that should be used for number parsing. + /// - Returns: Parsed number or nil if parsing will fail. + func number(from string: String, format: NumberFormatType) -> NSNumber? } diff --git a/Sources/Protocols/Views/PlaceholderConfigurable/PlaceholderConfigurable.swift b/Sources/Protocols/Views/PlaceholderConfigurable/PlaceholderConfigurable.swift new file mode 100644 index 00000000..c5c56653 --- /dev/null +++ b/Sources/Protocols/Views/PlaceholderConfigurable/PlaceholderConfigurable.swift @@ -0,0 +1,56 @@ +// +// Copyright (c) 2018 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit.UIView + +/// Protocol that defines attributes and methods for view with placeholder and regular state. +public protocol PlaceholderConfigurable { + + associatedtype ContentContainerViewType: UIView + associatedtype PlaceholderContainerViewType: UIView + + /// A view that will be shown when content will be received. + var contentContainerView: ContentContainerViewType { get } + /// A view that will be shown during loading content. + var placeholderContainerView: PlaceholderContainerViewType { get } + + associatedtype ContentViewModelType + associatedtype PlaceholderViewModelType + + typealias ContentLoadingViewModelType = ContentLoadingViewModel + + /// Configures view with content loading view model. + /// + /// - Parameter contentLoadingViewModel: Content loading view model with placeholder or content state. + func configureContentLoading(with contentLoadingViewModel: ContentLoadingViewModelType) + + /// Configures view with content view model. + /// + /// - Parameter contentViewModel: Content view model to configure content state. + func configure(contentViewModel: ContentViewModelType) + + /// Configures view with placeholder view model. + /// + /// - Parameter placeholderViewModel: Placeholder view model to configure placeholder state. + func configure(placeholderViewModel: PlaceholderViewModelType) + +}