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.
This commit is contained in:
Ivan Smolin 2018-09-13 20:07:04 +03:00
parent f2d523a9d2
commit 30bec8e9c7
19 changed files with 642 additions and 88 deletions

View File

@ -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.

View File

@ -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",

View File

@ -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 = "<group>"; };
674AF55B1EC45B1600038A8F /* UIActivityIndicatorView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicatorView+LoadingIndicator.swift"; sourceTree = "<group>"; };
675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseScrollContentController.swift; sourceTree = "<group>"; };
6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+AddSubviews.swift"; sourceTree = "<group>"; };
6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableSection+Extensions.swift"; sourceTree = "<group>"; };
676B22A1206A626D002E9F8A /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = "<group>"; };
67745267206249360024EEEF /* UITableView+PaginationWrappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+PaginationWrappable.swift"; sourceTree = "<group>"; };
@ -889,6 +921,11 @@
67952DDC1EB3280900B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = "<group>"; };
67952DDE1EB3285A00B3BA1A /* Info-iOS-Extensions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS-Extensions.plist"; sourceTree = "<group>"; };
67955D51206D216B0021ECD2 /* Singleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Singleton.swift; sourceTree = "<group>"; };
67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderConfigurable.swift; sourceTree = "<group>"; };
67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLoadingViewModel.swift; sourceTree = "<group>"; };
67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlaceholderConfigurable+DefaultImplementation.swift"; sourceTree = "<group>"; };
67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContentLoadingViewModel+Extensions.swift"; sourceTree = "<group>"; };
67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurableView+Extensions.swift"; sourceTree = "<group>"; };
679C77D41F98F78E0094BE10 /* AlertRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertRepresentable.swift; sourceTree = "<group>"; };
679C77D61F98F7A60094BE10 /* UIAlertController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extensions.swift"; sourceTree = "<group>"; };
67A1FF8E1EBCA09B00D6C89F /* UIImage+Spinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Spinner.swift"; sourceTree = "<group>"; };
@ -905,6 +942,9 @@
67E352562119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewTextConfigurable+Extensions.swift"; sourceTree = "<group>"; };
67E3525E2119B7570035BDDB /* BasePlaceholerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasePlaceholerView.swift; sourceTree = "<group>"; };
67E6C2341EBB32F5007842A6 /* SingleLoadCursor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLoadCursor.swift; sourceTree = "<group>"; };
67E9024A2125AEB4008EDF45 /* NSNumberConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNumberConvertible.swift; sourceTree = "<group>"; };
67E902502125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BuildInNumberTypes+NSNumberConvertible.swift"; sourceTree = "<group>"; };
67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+ExpandCollapseDisclosure.swift"; sourceTree = "<group>"; };
67EB7FBF206140E600BDD9FB /* TotalCountCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursor.swift; sourceTree = "<group>"; };
67EB7FC6206148D000BDD9FB /* TotalCountCursorListingResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorListingResult.swift; sourceTree = "<group>"; };
67EB7FCE20615B8900BDD9FB /* TotalCountCursorConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalCountCursorConfiguration.swift; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -1467,6 +1508,7 @@
children = (
67274768206CCC9D00725163 /* ViewBackground.swift */,
67274771206CCF1200725163 /* ViewText.swift */,
67990AC9213EA5B70040D195 /* ContentLoadingViewModel.swift */,
);
path = Views;
sourceTree = "<group>";
@ -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 = "<group>";
@ -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 = "<group>";
};
67990AC3213EA4BD0040D195 /* PlaceholderConfigurable */ = {
isa = PBXGroup;
children = (
67990AC4213EA4DB0040D195 /* PlaceholderConfigurable.swift */,
);
path = PlaceholderConfigurable;
sourceTree = "<group>";
};
67990ACE213EA62A0040D195 /* PlaceholderConfigurable */ = {
isa = PBXGroup;
children = (
67990AD5213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift */,
67990AD1213EA6790040D195 /* PlaceholderConfigurable+DefaultImplementation.swift */,
);
path = PlaceholderConfigurable;
sourceTree = "<group>";
};
67990ACF213EA6460040D195 /* InitializableView */ = {
isa = PBXGroup;
children = (
67ED2BE420B44F4300508B3E /* InitializableView+DefaultImplementation.swift */,
);
path = InitializableView;
sourceTree = "<group>";
};
67990AD0213EA6530040D195 /* ViewBackground */ = {
isa = PBXGroup;
children = (
6727476D206CCDDB00725163 /* ViewBackground+Configuration.swift */,
);
path = ViewBackground;
sourceTree = "<group>";
};
67990AE0213EB3C90040D195 /* ConfigurableView */ = {
isa = PBXGroup;
children = (
67990AE5213EB4080040D195 /* ConfigurableView+Extensions.swift */,
);
path = ConfigurableView;
sourceTree = "<group>";
};
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 = "<group>";
};
67E902552125B55E008EDF45 /* UIImageView */ = {
isa = PBXGroup;
children = (
67E902562125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift */,
);
path = UIImageView;
sourceTree = "<group>";
};
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 */,

View File

@ -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<ContentType, PlaceholderType> {
case placeholder(PlaceholderType)
case content(ContentType)
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}
}

View File

@ -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<Bool> {
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)
})
})
}
}
}

View File

@ -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) }
}
}

View File

@ -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)
}
}

View File

@ -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<ContentType, PlaceholderType> {
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<ContentType, PlaceholderType> {
return .placeholder(Array(repeating: (), count: numberOfItems))
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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?
}

View File

@ -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<ContentViewModelType, PlaceholderViewModelType>
/// 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)
}