Merge branch 'develop' into feature/rules_error
This commit is contained in:
commit
014567f726
@ -91,6 +91,12 @@
|
|||||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; };
|
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; };
|
||||||
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
|
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
|
||||||
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
|
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
|
||||||
|
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */; };
|
||||||
|
0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */; };
|
||||||
|
0A9D091F2433796500D2E6C0 /* NumericIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */; };
|
||||||
|
0A9D09202433796500D2E6C0 /* BarsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091A2433796500D2E6C0 /* BarsIndicatorView.swift */; };
|
||||||
|
0A9D09212433796500D2E6C0 /* CarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091B2433796500D2E6C0 /* CarouselIndicatorModel.swift */; };
|
||||||
|
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */; };
|
||||||
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; };
|
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; };
|
||||||
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; };
|
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; };
|
||||||
0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */; };
|
0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */; };
|
||||||
@ -480,6 +486,7 @@
|
|||||||
0A6682B4243769C700AD3CA1 /* TextViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewModel.swift; sourceTree = "<group>"; };
|
0A6682B4243769C700AD3CA1 /* TextViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewModel.swift; sourceTree = "<group>"; };
|
||||||
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = "<group>"; };
|
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = "<group>"; };
|
||||||
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = "<group>"; };
|
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||||
|
0A7918F423F5E7EA00772FF4 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
|
||||||
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
|
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
|
||||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||||
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; };
|
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; };
|
||||||
@ -494,6 +501,12 @@
|
|||||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
|
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsCarouselIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericCarouselIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D091A2433796500D2E6C0 /* BarsIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D091B2433796500D2E6C0 /* CarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarouselIndicatorModel.swift; sourceTree = "<group>"; };
|
||||||
|
0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarouselIndicator.swift; sourceTree = "<group>"; };
|
||||||
0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
|
0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
|
||||||
0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = "<group>"; };
|
0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = "<group>"; };
|
||||||
0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = "<group>"; };
|
0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = "<group>"; };
|
||||||
@ -891,6 +904,19 @@
|
|||||||
path = Protocols;
|
path = Protocols;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0A9D09162433796500D2E6C0 /* CarouselIndicator */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0A9D091B2433796500D2E6C0 /* CarouselIndicatorModel.swift */,
|
||||||
|
0A9D091C2433796500D2E6C0 /* CarouselIndicator.swift */,
|
||||||
|
0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */,
|
||||||
|
0A9D091A2433796500D2E6C0 /* BarsIndicatorView.swift */,
|
||||||
|
0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */,
|
||||||
|
0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */,
|
||||||
|
);
|
||||||
|
path = CarouselIndicator;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
0ABD1369237B18EE0081388D /* Views */ = {
|
0ABD1369237B18EE0081388D /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1012,13 +1038,6 @@
|
|||||||
path = Label;
|
path = Label;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
94FB5B83238D892800EB2193 /* Recovered References */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = "Recovered References";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
AA4FC2A323F4F69600E251DB /* RightVariable */ = {
|
AA4FC2A323F4F69600E251DB /* RightVariable */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1350,7 +1369,6 @@
|
|||||||
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */,
|
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */,
|
||||||
D29DF0CD21E404D4003B2FB9 /* Products */,
|
D29DF0CD21E404D4003B2FB9 /* Products */,
|
||||||
D29DF0E421E4F3C7003B2FB9 /* Frameworks */,
|
D29DF0E421E4F3C7003B2FB9 /* Frameworks */,
|
||||||
94FB5B83238D892800EB2193 /* Recovered References */,
|
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -1570,6 +1588,7 @@
|
|||||||
D29DF17D21E69E26003B2FB9 /* Views */ = {
|
D29DF17D21E69E26003B2FB9 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0A9D09162433796500D2E6C0 /* CarouselIndicator */,
|
||||||
9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */,
|
9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */,
|
||||||
01509D922327ECFB00EF99AA /* ProgressBar.swift */,
|
01509D922327ECFB00EF99AA /* ProgressBar.swift */,
|
||||||
9445890D2385C3F800DE9FD4 /* MultiProgressModel.swift */,
|
9445890D2385C3F800DE9FD4 /* MultiProgressModel.swift */,
|
||||||
@ -1740,6 +1759,7 @@
|
|||||||
D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */,
|
D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */,
|
||||||
D264FAA92440F97600D98315 /* CollectionView.swift */,
|
D264FAA92440F97600D98315 /* CollectionView.swift */,
|
||||||
0A5D59C323AD488600EFD9E9 /* Protocols */,
|
0A5D59C323AD488600EFD9E9 /* Protocols */,
|
||||||
|
0A7918F423F5E7EA00772FF4 /* ImageView.swift */,
|
||||||
);
|
);
|
||||||
path = BaseClasses;
|
path = BaseClasses;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1926,6 +1946,7 @@
|
|||||||
D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */,
|
D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */,
|
||||||
0A6682A42434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift in Sources */,
|
0A6682A42434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift in Sources */,
|
||||||
AA2AD116244EE46800BBFFE3 /* ListDeviceComplexLinkMedium.swift in Sources */,
|
AA2AD116244EE46800BBFFE3 /* ListDeviceComplexLinkMedium.swift in Sources */,
|
||||||
|
0A9D09202433796500D2E6C0 /* BarsIndicatorView.swift in Sources */,
|
||||||
D2E2A99423D8CCBC000B42E6 /* HeadlineBodyLinkModel.swift in Sources */,
|
D2E2A99423D8CCBC000B42E6 /* HeadlineBodyLinkModel.swift in Sources */,
|
||||||
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
|
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
|
||||||
D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */,
|
D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */,
|
||||||
@ -1985,6 +2006,7 @@
|
|||||||
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
||||||
C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */,
|
C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */,
|
||||||
014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */,
|
014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */,
|
||||||
|
0A9D091F2433796500D2E6C0 /* NumericIndicatorView.swift in Sources */,
|
||||||
D260106123D0C02A00764D80 /* StackItemModelProtocol.swift in Sources */,
|
D260106123D0C02A00764D80 /* StackItemModelProtocol.swift in Sources */,
|
||||||
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */,
|
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */,
|
||||||
012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */,
|
012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */,
|
||||||
@ -2022,9 +2044,11 @@
|
|||||||
D2A514672213885800345BFB /* MoleculeHeaderView.swift in Sources */,
|
D2A514672213885800345BFB /* MoleculeHeaderView.swift in Sources */,
|
||||||
D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */,
|
D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */,
|
||||||
01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */,
|
01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */,
|
||||||
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */,
|
0A9D09212433796500D2E6C0 /* CarouselIndicatorModel.swift in Sources */,
|
||||||
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */,
|
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */,
|
||||||
|
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */,
|
||||||
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
||||||
|
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */,
|
||||||
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
||||||
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
||||||
0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */,
|
0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */,
|
||||||
@ -2061,6 +2085,7 @@
|
|||||||
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
|
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
|
||||||
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
|
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
|
||||||
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
|
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
|
||||||
|
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */,
|
||||||
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
|
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
|
||||||
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
|
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
|
||||||
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
|
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
|
||||||
@ -2111,6 +2136,7 @@
|
|||||||
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
|
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
|
||||||
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
|
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
|
||||||
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
|
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
|
||||||
|
0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */,
|
||||||
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
|
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
|
||||||
0A6682B6243769C700AD3CA1 /* TextViewModel.swift in Sources */,
|
0A6682B6243769C700AD3CA1 /* TextViewModel.swift in Sources */,
|
||||||
9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */,
|
9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */,
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class Arrow: View {
|
open class Arrow: View {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@ -19,6 +20,41 @@ open class Arrow: View {
|
|||||||
return model as? ArrowModel
|
return model as? ArrowModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var direction: ArrowModel.Direction {
|
||||||
|
get { return ArrowModel.Direction(rawValue: degrees) ?? .right}
|
||||||
|
set { degrees = newValue.rawValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
open var isEnabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
arrowModel?.enabled = isEnabled
|
||||||
|
isUserInteractionEnabled = isEnabled
|
||||||
|
if isEnabled != oldValue {
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open var disabledColor: UIColor {
|
||||||
|
get { return arrowModel?.disabledColor.uiColor ?? .mvmCoolGray3 }
|
||||||
|
set { arrowModel?.disabledColor = Color(uiColor: newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open var color: UIColor {
|
||||||
|
get { return arrowModel?.color.uiColor ?? .mvmBlack }
|
||||||
|
set { arrowModel?.color = Color(uiColor: newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open var degrees: Float {
|
||||||
|
get { return arrowModel?.degrees ?? 0 }
|
||||||
|
set { arrowModel?.degrees = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
open var lineWidth: CGFloat {
|
||||||
|
get { return arrowModel?.lineWidth ?? 1 }
|
||||||
|
set { arrowModel?.lineWidth = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Constraints
|
// MARK: - Constraints
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -34,6 +70,18 @@ open class Arrow: View {
|
|||||||
widthConstraint?.isActive = true
|
widthConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -51,33 +99,32 @@ open class Arrow: View {
|
|||||||
// MARK: - Drawing
|
// MARK: - Drawing
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Draws the arrow pointing to the right and then rotates the arrow x degrees counter-clockwise.
|
||||||
open override func draw(_ rect: CGRect) {
|
open override func draw(_ rect: CGRect) {
|
||||||
super.draw(rect)
|
super.draw(rect)
|
||||||
|
|
||||||
arrowLayer.transform = CATransform3DIdentity
|
arrowLayer.transform = CATransform3DIdentity
|
||||||
drawShapeLayer()
|
drawShapeLayer()
|
||||||
|
|
||||||
if let degrees = arrowModel?.degrees {
|
let radians = CGFloat(degrees * Float.pi / 180)
|
||||||
let radians = CGFloat(degrees * Float.pi / 180)
|
arrowLayer.transform = CATransform3DMakeRotation(-radians, 0, 0, 1)
|
||||||
arrowLayer.transform = CATransform3DMakeRotation(-radians, 0.0, 0.0, 1.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func drawShapeLayer() {
|
private func drawShapeLayer() {
|
||||||
|
|
||||||
arrowLayer.frame = bounds
|
arrowLayer.frame = bounds
|
||||||
arrowLayer.strokeColor = arrowModel?.color.cgColor
|
arrowLayer.strokeColor = isEnabled ? color.cgColor : disabledColor.cgColor
|
||||||
arrowLayer.fillColor = UIColor.clear.cgColor
|
arrowLayer.fillColor = UIColor.clear.cgColor
|
||||||
arrowLayer.path = arrowPath()
|
arrowLayer.path = arrowPath()
|
||||||
arrowLayer.lineJoin = .miter
|
arrowLayer.lineJoin = .miter
|
||||||
arrowLayer.lineCap = .butt
|
arrowLayer.lineCap = .butt
|
||||||
arrowLayer.lineWidth = arrowModel?.lineWidth ?? 1
|
arrowLayer.lineWidth = lineWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
private func arrowPath() -> CGPath {
|
private func arrowPath() -> CGPath {
|
||||||
|
|
||||||
let length = max(bounds.size.height, bounds.size.width)
|
let length = max(bounds.size.height, bounds.size.width)
|
||||||
let inset = (arrowModel?.lineWidth ?? 1) / 2
|
let inset = lineWidth / 2
|
||||||
let midLength = length / 2
|
let midLength = length / 2
|
||||||
|
|
||||||
var startPoint = CGPoint(x: midLength, y: inset)
|
var startPoint = CGPoint(x: midLength, y: inset)
|
||||||
@ -97,4 +144,16 @@ open class Arrow: View {
|
|||||||
|
|
||||||
return bezierPath.cgPath
|
return bezierPath.cgPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let model = model as? ArrowModel else { return }
|
||||||
|
|
||||||
|
isEnabled = model.enabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,20 +8,47 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
open class ArrowModel: MoleculeModelProtocol {
|
open class ArrowModel: MoleculeModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public static var identifier: String = "arrow"
|
public static var identifier: String {
|
||||||
public var backgroundColor: Color?
|
return "arrow"
|
||||||
|
}
|
||||||
|
|
||||||
|
public var moleculeName: String?
|
||||||
|
public var backgroundColor: Color?
|
||||||
|
public var disabledColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||||
public var color: Color = Color(uiColor: .mvmBlack)
|
public var color: Color = Color(uiColor: .mvmBlack)
|
||||||
public var degrees: Float = 0
|
public var degrees: Float = 0
|
||||||
public var lineWidth: CGFloat = 1
|
public var lineWidth: CGFloat = 1
|
||||||
|
|
||||||
public var height: CGFloat = 12
|
public var height: CGFloat = 12
|
||||||
public var width: CGFloat = 12
|
public var width: CGFloat = 12
|
||||||
|
public var enabled: Bool = true
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Enum
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Conveniece for readability of arrow pointing direction.
|
||||||
|
public enum Direction: Float {
|
||||||
|
case right = 0
|
||||||
|
case upperRight = 45
|
||||||
|
case up = 90
|
||||||
|
case upperLeft = 135
|
||||||
|
case left = 180
|
||||||
|
case bottomLeft = 225
|
||||||
|
case down = 270
|
||||||
|
case bottomRight = 315
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public init() { }
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Keys
|
// MARK: - Keys
|
||||||
@ -30,12 +57,13 @@ open class ArrowModel: MoleculeModelProtocol {
|
|||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
|
case disabledColor
|
||||||
case color
|
case color
|
||||||
case degrees
|
case degrees
|
||||||
case size
|
|
||||||
case lineWidth
|
case lineWidth
|
||||||
case height
|
case height
|
||||||
case width
|
case width
|
||||||
|
case enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -44,12 +72,21 @@ open class ArrowModel: MoleculeModelProtocol {
|
|||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
|
|
||||||
|
if let disabledColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor) {
|
||||||
|
self.disabledColor = disabledColor
|
||||||
|
}
|
||||||
|
|
||||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
|
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
|
||||||
self.color = color
|
self.color = color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||||
|
self.enabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
if let degrees = try typeContainer.decodeIfPresent(Float.self, forKey: .degrees) {
|
if let degrees = try typeContainer.decodeIfPresent(Float.self, forKey: .degrees) {
|
||||||
self.degrees = degrees
|
self.degrees = degrees
|
||||||
}
|
}
|
||||||
@ -59,7 +96,7 @@ open class ArrowModel: MoleculeModelProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) {
|
if let height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) {
|
||||||
self.lineWidth = height
|
self.height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
if let width = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .width) {
|
if let width = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .width) {
|
||||||
@ -69,12 +106,14 @@ open class ArrowModel: MoleculeModelProtocol {
|
|||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(moleculeName, forKey: .moleculeName)
|
|
||||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||||
|
try container.encode(moleculeName, forKey: .moleculeName)
|
||||||
|
try container.encode(disabledColor, forKey: .disabledColor)
|
||||||
try container.encode(color, forKey: .color)
|
try container.encode(color, forKey: .color)
|
||||||
try container.encode(degrees, forKey: .degrees)
|
try container.encode(degrees, forKey: .degrees)
|
||||||
try container.encodeIfPresent(backgroundColor, forKey: .lineWidth)
|
try container.encode(lineWidth, forKey: .lineWidth)
|
||||||
try container.encode(width, forKey: .width)
|
try container.encode(width, forKey: .width)
|
||||||
try container.encode(height, forKey: .height)
|
try container.encode(height, forKey: .height)
|
||||||
|
try container.encode(enabled, forKey: .enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// BarsCarouselIndicatorModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 3/3/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class BarsCarouselIndicatorModel: CarouselIndicatorModel {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public class override var identifier: String {
|
||||||
|
return "barsCarouselIndicator"
|
||||||
|
}
|
||||||
|
|
||||||
|
public var currentIndicatorColor: Color = Color(uiColor: .mvmBlack)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case currentIndicatorColor
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public required init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
if let currentIndicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .currentIndicatorColor) {
|
||||||
|
self.currentIndicatorColor = currentIndicatorColor
|
||||||
|
}
|
||||||
|
|
||||||
|
try super.init(from: decoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(currentIndicatorColor, forKey: .currentIndicatorColor)
|
||||||
|
try super.encode(to: encoder)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,176 @@
|
|||||||
|
//
|
||||||
|
// BarIndicatorView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/3/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class BarsIndicatorView: CarouselIndicator {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Stored Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public let stackView: UIStackView = {
|
||||||
|
let stackView = UIStackView()
|
||||||
|
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
stackView.isAccessibilityElement = false
|
||||||
|
stackView.axis = .horizontal
|
||||||
|
stackView.alignment = .bottom
|
||||||
|
stackView.distribution = .equalSpacing
|
||||||
|
stackView.spacing = 6
|
||||||
|
return stackView
|
||||||
|
}()
|
||||||
|
|
||||||
|
public var barReferences: [(view: View, constraint: NSLayoutConstraint)] = []
|
||||||
|
|
||||||
|
// Dimensions are based on InVision Design Guidelines.
|
||||||
|
public static let indicatorBarWidth: CGFloat = 24
|
||||||
|
public static let indicatorBarHeight: (selected: CGFloat, unselected: CGFloat) = (selected: 4, unselected: 1)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Computed Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Convenience to access the model.
|
||||||
|
public var barsCarouselIndicatorModel: BarsCarouselIndicatorModel? {
|
||||||
|
return model as? BarsCarouselIndicatorModel
|
||||||
|
}
|
||||||
|
|
||||||
|
open override var isEnabled: Bool {
|
||||||
|
didSet {
|
||||||
|
for (i, bar) in barReferences.enumerated() {
|
||||||
|
if i == currentIndex {
|
||||||
|
bar.view.backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor
|
||||||
|
} else {
|
||||||
|
bar.view.backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Colors the currently selected index, unique from other indicators
|
||||||
|
public var currentIndicatorColor: UIColor {
|
||||||
|
get { return barsCarouselIndicatorModel?.currentIndicatorColor.uiColor ?? indicatorColor }
|
||||||
|
set (newColor) {
|
||||||
|
barsCarouselIndicatorModel?.currentIndicatorColor = Color(uiColor: newColor)
|
||||||
|
|
||||||
|
if isEnabled && !barReferences.isEmpty {
|
||||||
|
barReferences[currentIndex].view.backgroundColor = newColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var indicatorColor: UIColor {
|
||||||
|
get { return super.indicatorColor }
|
||||||
|
set (newColor) {
|
||||||
|
super.indicatorColor = newColor
|
||||||
|
|
||||||
|
if isEnabled {
|
||||||
|
for (i, barTuple) in barReferences.enumerated() {
|
||||||
|
barTuple.view.backgroundColor = i == currentIndex ? currentIndicatorColor : newColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Setup
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
addSubview(stackView)
|
||||||
|
isUserInteractionEnabled = false
|
||||||
|
isAccessibilityElement = false
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
stackView.heightAnchor.constraint(equalToConstant: 4),
|
||||||
|
heightAnchor.constraint(equalTo: stackView.heightAnchor),
|
||||||
|
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
stackView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
bottomAnchor.constraint(equalTo: stackView.bottomAnchor),
|
||||||
|
trailingAnchor.constraint(equalTo: stackView.trailingAnchor)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func generateBars() {
|
||||||
|
|
||||||
|
var bars = [(View, NSLayoutConstraint)]()
|
||||||
|
|
||||||
|
let ordinalFormatter = NumberFormatter()
|
||||||
|
ordinalFormatter.numberStyle = .ordinal
|
||||||
|
|
||||||
|
for i in 0..<numberOfPages {
|
||||||
|
let bar = View()
|
||||||
|
bar.accessibilityTraits = .button
|
||||||
|
bar.isAccessibilityElement = true
|
||||||
|
if let accessibleValueFormat = accessibilityValueFormat, let accessibleIndex = ordinalFormatter.string(from: NSNumber(value: i + 1)) {
|
||||||
|
bar.accessibilityLabel = String(format: accessibleValueFormat, accessibleIndex, numberOfPages)
|
||||||
|
}
|
||||||
|
bar.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint")
|
||||||
|
bar.widthAnchor.constraint(equalToConstant: BarsIndicatorView.indicatorBarWidth).isActive = true
|
||||||
|
bar.backgroundColor = isEnabled ? (i == currentIndex ? currentIndicatorColor : indicatorColor) : disabledIndicatorColor
|
||||||
|
let barHeight = i == currentIndex ? BarsIndicatorView.indicatorBarHeight.selected : BarsIndicatorView.indicatorBarHeight.unselected
|
||||||
|
let heightConstraint = bar.heightAnchor.constraint(equalToConstant: barHeight)
|
||||||
|
heightConstraint.isActive = true
|
||||||
|
|
||||||
|
stackView.addArrangedSubview(bar)
|
||||||
|
bars.append((bar, heightConstraint))
|
||||||
|
}
|
||||||
|
|
||||||
|
accessibilityElements = stackView.arrangedSubviews
|
||||||
|
barReferences = bars
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func assessTouchOf(_ touchPoint_X: CGFloat) {
|
||||||
|
|
||||||
|
currentIndex = barReferences.firstIndex { $0.0.frame.maxX >= touchPoint_X && $0.0.frame.minX <= touchPoint_X } ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let model = model as? BarsCarouselIndicatorModel else { return }
|
||||||
|
|
||||||
|
currentIndicatorColor = model.currentIndicatorColor.uiColor
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - IndicatorViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func reset() {
|
||||||
|
super.reset()
|
||||||
|
barReferences.forEach { $0.view.removeFromSuperview() }
|
||||||
|
barReferences = []
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func updateUI(previousIndex: Int, newIndex: Int, totalCount: Int, isAnimated: Bool) {
|
||||||
|
|
||||||
|
guard newIndex < totalCount else { return }
|
||||||
|
|
||||||
|
guard !barReferences.isEmpty else {
|
||||||
|
generateBars()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let expression = {
|
||||||
|
self.barReferences[previousIndex].view.backgroundColor = self.isEnabled ? self.indicatorColor : self.disabledIndicatorColor
|
||||||
|
self.barReferences[newIndex].view.backgroundColor = self.isEnabled ? self.currentIndicatorColor : self.disabledIndicatorColor
|
||||||
|
self.barReferences[previousIndex].constraint.constant = BarsIndicatorView.indicatorBarHeight.unselected
|
||||||
|
self.barReferences[newIndex].constraint.constant = BarsIndicatorView.indicatorBarHeight.selected
|
||||||
|
self.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
isAnimated ? UIView.animate(withDuration: 0.3) { expression() } : expression()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,246 @@
|
|||||||
|
//
|
||||||
|
// CarouselIndicator.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 1/30/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var topConstraint: NSLayoutConstraint?
|
||||||
|
public var bottomConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var uiGestures: Set<UIGestureRecognizer> = []
|
||||||
|
|
||||||
|
/// Convenience to access the model.
|
||||||
|
public var carouselIndicatorModel: CarouselIndicatorModel? {
|
||||||
|
return model as? CarouselIndicatorModel
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set this closure to perform an action when a different indicator was selected.
|
||||||
|
/// Passes through oldIndex and newIndex, respectively.
|
||||||
|
public var indicatorTouchAction: ((CarouselPageControlProtocol) -> ())?
|
||||||
|
|
||||||
|
open override var isEnabled: Bool {
|
||||||
|
didSet { isUserInteractionEnabled = isEnabled }
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Computed Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private(set) var previousIndex = 0
|
||||||
|
|
||||||
|
public var currentIndex: Int {
|
||||||
|
get { return carouselIndicatorModel?.currentIndex ?? 0 }
|
||||||
|
set (newIndex) {
|
||||||
|
previousIndex = currentIndex
|
||||||
|
carouselIndicatorModel?.currentIndex = newIndex
|
||||||
|
|
||||||
|
if previousIndex != newIndex {
|
||||||
|
updateUI(previousIndex: previousIndex,
|
||||||
|
newIndex: newIndex,
|
||||||
|
totalCount: numberOfPages,
|
||||||
|
isAnimated: carouselIndicatorModel?.animated ?? true)
|
||||||
|
performAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Holds the total number of pages displayed by the carousel.
|
||||||
|
/// Updating this property will potentially update the UI.
|
||||||
|
public var numberOfPages: Int {
|
||||||
|
get { return carouselIndicatorModel?.numberOfPages ?? 0 }
|
||||||
|
set (newTotal) {
|
||||||
|
guard numberOfPages != newTotal else { return }
|
||||||
|
|
||||||
|
carouselIndicatorModel?.numberOfPages = newTotal
|
||||||
|
reset()
|
||||||
|
isHidden = (carouselIndicatorModel?.hidesForSinglePage ?? false) && newTotal <= 1
|
||||||
|
updateUI(previousIndex: previousIndex,
|
||||||
|
newIndex: currentIndex,
|
||||||
|
totalCount: newTotal,
|
||||||
|
isAnimated: carouselIndicatorModel?.animated ?? true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var disabledIndicatorColor: UIColor {
|
||||||
|
get { return carouselIndicatorModel?.disabledIndicatorColor.uiColor ?? .mvmCoolGray3 }
|
||||||
|
set { carouselIndicatorModel?.disabledIndicatorColor = Color(uiColor: newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var indicatorColor: UIColor {
|
||||||
|
get { return carouselIndicatorModel?.indicatorColor.uiColor ?? .mvmBlack }
|
||||||
|
set { carouselIndicatorModel?.indicatorColor = Color(uiColor: newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessibilityValueFormat: String? {
|
||||||
|
return MVMCoreUIUtility.hardcodedString(withKey: (carouselIndicatorModel?.accessibilityHasSlidesInsteadOfPage ?? false) ? "MVMCoreUIPageControlslides_currentpage_index" : "MVMCoreUIPageControl_currentpage_index")
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience override init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityTraits = .adjustable
|
||||||
|
setupGestures()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - UITouch
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private func setupGestures() {
|
||||||
|
|
||||||
|
let tap = UITapGestureRecognizer(target: self, action: #selector(indicatorTapped))
|
||||||
|
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeft))
|
||||||
|
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeRight))
|
||||||
|
|
||||||
|
leftSwipe.direction = .left
|
||||||
|
rightSwipe.direction = .right
|
||||||
|
|
||||||
|
addGestureRecognizer(tap)
|
||||||
|
addGestureRecognizer(leftSwipe)
|
||||||
|
addGestureRecognizer(rightSwipe)
|
||||||
|
|
||||||
|
uiGestures.insert(tap)
|
||||||
|
uiGestures.insert(leftSwipe)
|
||||||
|
uiGestures.insert(rightSwipe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func incrementCurrentIndex() {
|
||||||
|
currentIndex = (currentIndex + 1) % numberOfPages
|
||||||
|
}
|
||||||
|
|
||||||
|
func decrementCurrentIndex() {
|
||||||
|
let newIndex = currentIndex - 1
|
||||||
|
currentIndex = newIndex < 0 ? numberOfPages - 1 : newIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increments the currentIndex value.
|
||||||
|
@objc func swipeLeft() {
|
||||||
|
incrementCurrentIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrement the currentIndex value
|
||||||
|
@objc func swipeRight() {
|
||||||
|
decrementCurrentIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles tap logic for Indicator
|
||||||
|
@objc func indicatorTapped(_ tapGesture: UITapGestureRecognizer?) {
|
||||||
|
|
||||||
|
let touchPoint = tapGesture?.location(in: self)
|
||||||
|
let touchPoint_X = touchPoint?.x ?? 0.0
|
||||||
|
|
||||||
|
assessTouchOf(touchPoint_X)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assessTouchOf(_ touchPoint_X: CGFloat) { }
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open func updateUI(previousIndex: Int, newIndex: Int, totalCount: Int, isAnimated: Bool) { }
|
||||||
|
|
||||||
|
public func performAction() {
|
||||||
|
|
||||||
|
sendActions(for: .valueChanged)
|
||||||
|
indicatorTouchAction?(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func scrollViewDidScroll(_ collectionView: UICollectionView) { }
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let model = model as? CarouselIndicatorModel else { return }
|
||||||
|
|
||||||
|
indicatorColor = model.indicatorColor.uiColor
|
||||||
|
disabledIndicatorColor = model.disabledIndicatorColor.uiColor
|
||||||
|
currentIndex = model.currentIndex
|
||||||
|
isEnabled = model.enabled
|
||||||
|
|
||||||
|
formatAccessibilityValue(index: currentIndex + 1, total: numberOfPages)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Accessibility
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func accessibilityIncrement() {
|
||||||
|
|
||||||
|
adjustAccessibility(toPage: currentIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func accessibilityDecrement() {
|
||||||
|
|
||||||
|
adjustAccessibility(toPage: currentIndex - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatAccessibilityValue(index: Int, total: Int) {
|
||||||
|
|
||||||
|
let ordinalFormatter = NumberFormatter()
|
||||||
|
ordinalFormatter.numberStyle = .ordinal
|
||||||
|
|
||||||
|
guard let accessibleFormat = accessibilityValueFormat,
|
||||||
|
let accessibleIndex = ordinalFormatter.string(from: NSNumber(value: index))
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
accessibilityValue = String(format: accessibleFormat, accessibleIndex, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustAccessibility(toPage index: Int) {
|
||||||
|
|
||||||
|
formatAccessibilityValue(index: index, total: numberOfPages)
|
||||||
|
|
||||||
|
if (index < numberOfPages && index >= 0) || carouselIndicatorModel?.alwaysSendAction ?? false {
|
||||||
|
carouselIndicatorModel?.animated = false
|
||||||
|
previousIndex = currentIndex
|
||||||
|
currentIndex = index
|
||||||
|
performAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTopBottomSpace(constant: CGFloat) {
|
||||||
|
|
||||||
|
bottomConstraint?.constant = constant
|
||||||
|
topConstraint?.constant = constant
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
//
|
||||||
|
// CarouselIndicatorModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/3/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public class var identifier: String {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
public var backgroundColor: Color?
|
||||||
|
public var moleculeName: String?
|
||||||
|
public var numberOfPages: Int = 0
|
||||||
|
|
||||||
|
/// Sets the current Index to focus on.
|
||||||
|
public var currentIndex: Int = 0
|
||||||
|
public var animated: Bool = true
|
||||||
|
public var hidesForSinglePage: Bool = false
|
||||||
|
/// Set true to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is false
|
||||||
|
public var accessibilityHasSlidesInsteadOfPage: Bool = false
|
||||||
|
public var enabled: Bool = true
|
||||||
|
public var disabledIndicatorColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||||
|
public var indicatorColor: Color = Color(uiColor: .mvmBlack)
|
||||||
|
public var position: Float?
|
||||||
|
|
||||||
|
/// Allows sendActions() to trigger even if index is already at min/max index.
|
||||||
|
public var alwaysSendAction = false
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case moleculeName
|
||||||
|
case backgroundColor
|
||||||
|
case currentIndex
|
||||||
|
case numberOfPages
|
||||||
|
case alwaysSendAction
|
||||||
|
case animated
|
||||||
|
case hidesForSinglePage
|
||||||
|
case accessibilityHasSlidesInsteadOfPage
|
||||||
|
case enabled
|
||||||
|
case disabledIndicatorColor
|
||||||
|
case indicatorColor
|
||||||
|
case position
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
moleculeName = try typeContainer.decodeIfPresent(String.self, forKey: .moleculeName)
|
||||||
|
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||||
|
|
||||||
|
if let currentIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .currentIndex) {
|
||||||
|
self.currentIndex = currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
if let alwaysSendAction = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysSendAction) {
|
||||||
|
self.alwaysSendAction = alwaysSendAction
|
||||||
|
}
|
||||||
|
|
||||||
|
if let position = try typeContainer.decodeIfPresent(Float.self, forKey: .position) {
|
||||||
|
self.position = position
|
||||||
|
}
|
||||||
|
|
||||||
|
if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) {
|
||||||
|
self.animated = animated
|
||||||
|
}
|
||||||
|
|
||||||
|
if let hidesForSinglePage = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidesForSinglePage) {
|
||||||
|
self.hidesForSinglePage = hidesForSinglePage
|
||||||
|
}
|
||||||
|
|
||||||
|
if let accessibilityHasSlidesInsteadOfPage = try typeContainer.decodeIfPresent(Bool.self, forKey: .accessibilityHasSlidesInsteadOfPage) {
|
||||||
|
self.accessibilityHasSlidesInsteadOfPage = accessibilityHasSlidesInsteadOfPage
|
||||||
|
}
|
||||||
|
|
||||||
|
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||||
|
self.enabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
if let disabledIndicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledIndicatorColor) {
|
||||||
|
self.disabledIndicatorColor = disabledIndicatorColor
|
||||||
|
}
|
||||||
|
|
||||||
|
if let indicatorColor = try typeContainer.decodeIfPresent(Color.self, forKey: .indicatorColor) {
|
||||||
|
self.indicatorColor = indicatorColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
|
||||||
|
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||||
|
try container.encode(numberOfPages, forKey: .numberOfPages)
|
||||||
|
try container.encode(currentIndex, forKey: .currentIndex)
|
||||||
|
try container.encode(alwaysSendAction, forKey: .alwaysSendAction)
|
||||||
|
try container.encode(animated, forKey: .animated)
|
||||||
|
try container.encode(hidesForSinglePage, forKey: .hidesForSinglePage)
|
||||||
|
try container.encode(accessibilityHasSlidesInsteadOfPage, forKey: .accessibilityHasSlidesInsteadOfPage)
|
||||||
|
try container.encode(enabled, forKey: .enabled)
|
||||||
|
try container.encode(disabledIndicatorColor, forKey: .disabledIndicatorColor)
|
||||||
|
try container.encode(indicatorColor, forKey: .indicatorColor)
|
||||||
|
try container.encodeIfPresent(position, forKey: .position)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// NumericCarouselIndicatorModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 3/3/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class NumericCarouselIndicatorModel: CarouselIndicatorModel {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public class override var identifier: String {
|
||||||
|
return "numericCarouselIndicator"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// NumericIndicatorView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/3/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class NumericIndicatorView: CarouselIndicator {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Text to display the current count of total pages for viewing.
|
||||||
|
open var pageCount: Label = {
|
||||||
|
let label = Label.commonLabelB2(true)
|
||||||
|
label.isAccessibilityElement = false
|
||||||
|
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
label.textAlignment = .center
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let leftArrow: Arrow = {
|
||||||
|
let arrow = Arrow(model: ArrowModel(), nil, nil)
|
||||||
|
arrow.isAccessibilityElement = false
|
||||||
|
arrow.direction = .left
|
||||||
|
arrow.pinHeightAndWidth()
|
||||||
|
return arrow
|
||||||
|
}()
|
||||||
|
|
||||||
|
let rightArrow: Arrow = {
|
||||||
|
let arrow = Arrow(model: ArrowModel(), nil, nil)
|
||||||
|
arrow.pinHeightAndWidth()
|
||||||
|
return arrow
|
||||||
|
}()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Computed Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override var isEnabled: Bool {
|
||||||
|
didSet { setViewColor(isEnabled ? indicatorColor : disabledIndicatorColor) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the color for pageCount text, left arrow and right arrow.
|
||||||
|
public override var indicatorColor: UIColor {
|
||||||
|
get { return super.indicatorColor }
|
||||||
|
set (newColor) {
|
||||||
|
super.indicatorColor = newColor
|
||||||
|
|
||||||
|
if isEnabled {
|
||||||
|
setViewColor(newColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
pageCount.updateView(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Setup
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
|
||||||
|
addSubview(pageCount)
|
||||||
|
addSubview(leftArrow)
|
||||||
|
addSubview(rightArrow)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
pageCount.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||||
|
pageCount.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
bottomAnchor.constraint(equalTo: pageCount.bottomAnchor),
|
||||||
|
leftArrow.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
rightArrow.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
leftArrow.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
pageCount.leadingAnchor.constraint(equalTo: leftArrow.trailingAnchor, constant: Padding.Two),
|
||||||
|
rightArrow.leadingAnchor.constraint(equalTo: pageCount.trailingAnchor, constant: Padding.Two),
|
||||||
|
trailingAnchor.constraint(equalTo: rightArrow.trailingAnchor)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func assessTouchOf(_ touchPoint_X: CGFloat) {
|
||||||
|
|
||||||
|
if touchPoint_X > bounds.width / 2 {
|
||||||
|
incrementCurrentIndex()
|
||||||
|
} else {
|
||||||
|
decrementCurrentIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setViewColor(_ newColor: UIColor) {
|
||||||
|
|
||||||
|
pageCount.textColor = newColor
|
||||||
|
leftArrow.color = newColor
|
||||||
|
rightArrow.color = newColor
|
||||||
|
rightArrow.setNeedsDisplay()
|
||||||
|
leftArrow.setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - IndicatorViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func updateUI(previousIndex oldIndex: Int, newIndex: Int, totalCount: Int, isAnimated: Bool) {
|
||||||
|
|
||||||
|
pageCount.text = "\(newIndex + 1)/\(totalCount)"
|
||||||
|
formatAccessibilityValue(index: newIndex + 1, total: totalCount)
|
||||||
|
layoutIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -44,6 +44,10 @@ import UIKit
|
|||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
public required init?(coder aDecoder: NSCoder) {
|
public required init?(coder aDecoder: NSCoder) {
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,6 +137,8 @@ import Foundation
|
|||||||
|
|
||||||
// Other Organisms
|
// Other Organisms
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: Carousel.self, viewModelClass: CarouselModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: Carousel.self, viewModelClass: CarouselModel.self)
|
||||||
|
MoleculeObjectMapping.shared()?.register(viewClass: BarsIndicatorView.self, viewModelClass: BarsCarouselIndicatorModel.self)
|
||||||
|
MoleculeObjectMapping.shared()?.register(viewClass: NumericIndicatorView.self, viewModelClass: NumericCarouselIndicatorModel.self)
|
||||||
|
|
||||||
// Designed List Items
|
// Designed List Items
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self)
|
||||||
|
|||||||
@ -8,11 +8,12 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
@objcMembers public class ListOneColumnFullWidthTextAllTextAndLinks: TableViewCell {
|
@objcMembers public class ListOneColumnFullWidthTextAllTextAndLinks: TableViewCell {
|
||||||
|
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
|
|
||||||
var stack: Stack<StackModel>
|
var stack: Stack<StackModel>
|
||||||
let eyebrow = Label.commonLabelB3(true)
|
let eyebrow = Label.commonLabelB3(true)
|
||||||
let headline = Label.commonLabelH3(true)
|
let headline = Label.commonLabelH3(true)
|
||||||
@ -26,7 +27,7 @@ import Foundation
|
|||||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
stack = Stack<StackModel>.createStack(with: [eyebrow, headline, subHeadline, body, link])
|
stack = Stack<StackModel>.createStack(with: [eyebrow, headline, subHeadline, body, link])
|
||||||
stack.stackModel?.spacing = 0
|
stack.stackModel?.spacing = 0
|
||||||
stack.stackModel?.molecules[4].spacing = 2
|
stack.stackModel?.molecules[4].spacing = 8
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,13 +38,14 @@ import Foundation
|
|||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
// MARK: - View Lifecycle
|
// MARK: - View Lifecycle
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
|
|
||||||
override open func setupView() {
|
override open func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
addMolecule(stack)
|
addMolecule(stack)
|
||||||
stack.restack()
|
stack.restack()
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? ListOneColumnFullWidthTextAllTextAndLinksModel else { return }
|
guard let model = model as? ListOneColumnFullWidthTextAllTextAndLinksModel else { return }
|
||||||
stack.updateContainedMolecules(with: [model.eyebrow,
|
stack.updateContainedMolecules(with: [model.eyebrow,
|
||||||
|
|||||||
@ -10,17 +10,30 @@ import Foundation
|
|||||||
|
|
||||||
|
|
||||||
@objcMembers public class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol {
|
@objcMembers public class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override class var identifier: String {
|
public override class var identifier: String {
|
||||||
return "carouselItem"
|
return "carouselItem"
|
||||||
}
|
}
|
||||||
|
|
||||||
public var peakingUI: Bool?
|
public var peakingUI: Bool?
|
||||||
public var peakingArrowColor: Color?
|
public var peakingArrowColor: Color?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case peakingUI
|
case peakingUI
|
||||||
case peakingArrowColor
|
case peakingArrowColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI)
|
peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI)
|
||||||
|
|||||||
@ -21,11 +21,19 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco
|
|||||||
case backgroundColor
|
case backgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(with moleculeModel: MoleculeModelProtocol) {
|
public init(with moleculeModel: MoleculeModelProtocol) {
|
||||||
molecule = moleculeModel
|
molecule = moleculeModel
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
molecule = try typeContainer.decodeModel(codingKey: .molecule)
|
molecule = try typeContainer.decodeModel(codingKey: .molecule)
|
||||||
|
|||||||
@ -8,6 +8,15 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
/// Contracts behavior between carousel and its page control.
|
||||||
|
public protocol CarouselPageControlProtocol {
|
||||||
|
var currentIndex: Int { get set }
|
||||||
|
var numberOfPages: Int { get set }
|
||||||
|
var indicatorTouchAction: ((CarouselPageControlProtocol) -> ())? { get set }
|
||||||
|
func scrollViewDidScroll(_ collectionView: UICollectionView)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open class Carousel: View {
|
open class Carousel: View {
|
||||||
|
|
||||||
public let collectionView = CollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
|
public let collectionView = CollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
|
||||||
@ -30,7 +39,7 @@ open class Carousel: View {
|
|||||||
|
|
||||||
/// The models for the molecules.
|
/// The models for the molecules.
|
||||||
var molecules: [MoleculeModelProtocol]?
|
var molecules: [MoleculeModelProtocol]?
|
||||||
|
|
||||||
/// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%.
|
/// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%.
|
||||||
public var itemAlignment = UICollectionView.ScrollPosition.left
|
public var itemAlignment = UICollectionView.ScrollPosition.left
|
||||||
|
|
||||||
@ -41,10 +50,11 @@ open class Carousel: View {
|
|||||||
public var collectionViewHeight: NSLayoutConstraint?
|
public var collectionViewHeight: NSLayoutConstraint?
|
||||||
|
|
||||||
/// The view that we use for paging
|
/// The view that we use for paging
|
||||||
public var pagingView: (UIView & MVMCoreUIPagingProtocol)?
|
public var pagingView: (UIView & CarouselPageControlProtocol)?
|
||||||
|
|
||||||
/// If the carousel should loop after scrolling past the first and final cells.
|
/// If the carousel should loop after scrolling past the first and final cells.
|
||||||
var loop = false
|
var loop = false
|
||||||
|
|
||||||
private var dragging = false
|
private var dragging = false
|
||||||
|
|
||||||
// For adding pager
|
// For adding pager
|
||||||
@ -81,6 +91,8 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
@ -103,16 +115,21 @@ open class Carousel: View {
|
|||||||
layoutCollection()
|
layoutCollection()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeViewProtocol
|
//--------------------------------------------------
|
||||||
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
self.delegateObject = delegateObject
|
self.delegateObject = delegateObject
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let carouselModel = model as? CarouselModel else { return }
|
guard let carouselModel = model as? CarouselModel else { return }
|
||||||
|
|
||||||
collectionView.backgroundColor = backgroundColor
|
collectionView.backgroundColor = backgroundColor
|
||||||
collectionView.layer.borderColor = backgroundColor?.cgColor
|
collectionView.layer.borderColor = backgroundColor?.cgColor
|
||||||
collectionView.layer.borderWidth = (carouselModel.border ?? false) ? 1 : 0
|
collectionView.layer.borderWidth = (carouselModel.border ?? false) ? 1 : 0
|
||||||
backgroundColor = .white
|
backgroundColor = .white
|
||||||
|
|
||||||
registerCells(with: carouselModel, delegateObject: delegateObject)
|
registerCells(with: carouselModel, delegateObject: delegateObject)
|
||||||
setupLayout(with: carouselModel)
|
setupLayout(with: carouselModel)
|
||||||
prepareMolecules(with: carouselModel)
|
prepareMolecules(with: carouselModel)
|
||||||
@ -129,60 +146,71 @@ open class Carousel: View {
|
|||||||
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
|
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
|
||||||
|
|
||||||
pageIndex = carouselModel.index
|
pageIndex = carouselModel.index
|
||||||
pagingView?.setPage(carouselModel.index)
|
pagingView?.currentIndex = carouselModel.index
|
||||||
collectionView.reloadData()
|
collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - JSON Setters
|
// MARK: - JSON Setters
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// Updates the layout being used
|
/// Updates the layout being used
|
||||||
|
|
||||||
func setupLayout(with carouselModel: CarouselModel?) {
|
func setupLayout(with carouselModel: CarouselModel?) {
|
||||||
|
|
||||||
let layout = UICollectionViewFlowLayout()
|
let layout = UICollectionViewFlowLayout()
|
||||||
layout.scrollDirection = .horizontal
|
layout.scrollDirection = .horizontal
|
||||||
layout.minimumLineSpacing = CGFloat(carouselModel?.spacing ?? 1)
|
layout.minimumLineSpacing = CGFloat(carouselModel?.spacing ?? 1)
|
||||||
layout.minimumInteritemSpacing = 0
|
layout.minimumInteritemSpacing = 0
|
||||||
collectionView.collectionViewLayout = layout
|
collectionView.collectionViewLayout = layout
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareMolecules(with carouselModel: CarouselModel?) {
|
func prepareMolecules(with carouselModel: CarouselModel?) {
|
||||||
guard let newMolecules = carouselModel?.molecules else {
|
guard let newMolecules = carouselModel?.molecules else {
|
||||||
numberOfPages = 0
|
numberOfPages = 0
|
||||||
molecules = nil
|
molecules = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfPages = newMolecules.count
|
numberOfPages = newMolecules.count
|
||||||
molecules = newMolecules
|
molecules = newMolecules
|
||||||
|
|
||||||
if carouselModel?.loop ?? false && newMolecules.count > 2 {
|
if carouselModel?.loop ?? false && newMolecules.count > 2 {
|
||||||
// Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell).
|
// Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell).
|
||||||
loop = true
|
loop = true
|
||||||
|
|
||||||
molecules?.insert(newMolecules.last!, at: 0)
|
molecules?.insert(newMolecules.last!, at: 0)
|
||||||
molecules?.insert(newMolecules[(newMolecules.count - 2)], at: 0)
|
molecules?.insert(newMolecules[(newMolecules.count - 2)], at: 0)
|
||||||
molecules?.append(newMolecules.first!)
|
molecules?.append(newMolecules.first!)
|
||||||
molecules?.append(newMolecules[1])
|
molecules?.append(newMolecules[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
pageIndex = 0
|
pageIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the paging molecule
|
/// Sets up the paging molecule
|
||||||
open func setupPagingMolecule(_ molecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)?, delegateObject: MVMCoreUIDelegateObject?) {
|
open func setupPagingMolecule(_ molecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)?, delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil
|
var pagingView: (UIView & CarouselPageControlProtocol)? = nil
|
||||||
if let molecule = molecule {
|
if let molecule = molecule {
|
||||||
pagingView = MoleculeObjectMapping.shared()?.createMolecule(molecule, delegateObject: delegateObject) as? (UIView & MVMCoreUIPagingProtocol)
|
pagingView = MoleculeObjectMapping.shared()?.createMolecule(molecule, delegateObject: delegateObject) as? (UIView & CarouselPageControlProtocol)
|
||||||
}
|
}
|
||||||
addPaging(view: pagingView, position: (CGFloat(molecule?.position ?? 20)))
|
|
||||||
|
addPaging(view: pagingView , position: (CGFloat(molecule?.position ?? 20)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers the cells with the collection view
|
/// Registers the cells with the collection view
|
||||||
func registerCells(with carouselModel: CarouselModel, delegateObject: MVMCoreUIDelegateObject?) {
|
func registerCells(with carouselModel: CarouselModel, delegateObject: MVMCoreUIDelegateObject?) {
|
||||||
|
|
||||||
for molecule in carouselModel.molecules {
|
for molecule in carouselModel.molecules {
|
||||||
if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) {
|
if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) {
|
||||||
collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier)
|
collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
// MARK: - Convenience
|
// MARK: - Convenience
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
/// Returns the (identifier, class) of the molecule for the given map.
|
/// Returns the (identifier, class) of the molecule for the given map.
|
||||||
func getMoleculeInfo(with molecule: MoleculeModelProtocol, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
func getMoleculeInfo(with molecule: MoleculeModelProtocol, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
||||||
guard let className = MoleculeObjectMapping.shared()?.getMoleculeClass(molecule) else {
|
guard let className = MoleculeObjectMapping.shared()?.getMoleculeClass(molecule) else {
|
||||||
@ -192,44 +220,47 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a paging view. Centers it horizontally with the collection view. The position is the vertical distance from the center of the page view to the bottom of the collection view.
|
/// Adds a paging view. Centers it horizontally with the collection view. The position is the vertical distance from the center of the page view to the bottom of the collection view.
|
||||||
open func addPaging(view: (UIView & MVMCoreUIPagingProtocol)?, position: CGFloat) {
|
open func addPaging(view: (UIView & CarouselPageControlProtocol)?, position: CGFloat) {
|
||||||
|
|
||||||
pagingView?.removeFromSuperview()
|
pagingView?.removeFromSuperview()
|
||||||
guard let pagingView = view else {
|
bottomPin?.isActive = false
|
||||||
bottomPin?.isActive = false
|
|
||||||
|
guard var pagingView = view else {
|
||||||
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
||||||
bottomPin?.isActive = true
|
bottomPin?.isActive = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pagingView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(pagingView)
|
addSubview(pagingView)
|
||||||
pagingView.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor).isActive = true
|
pagingView.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor).isActive = true
|
||||||
collectionView.bottomAnchor.constraint(equalTo: pagingView.centerYAnchor, constant: position).isActive = true
|
collectionView.bottomAnchor.constraint(equalTo: pagingView.centerYAnchor, constant: position).isActive = true
|
||||||
bottomAnchor.constraint(greaterThanOrEqualTo: pagingView.bottomAnchor).isActive = true
|
bottomAnchor.constraint(greaterThanOrEqualTo: pagingView.bottomAnchor).isActive = true
|
||||||
bottomPin?.isActive = false
|
|
||||||
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
bottomPin = bottomAnchor.constraint(equalTo: collectionView.bottomAnchor)
|
||||||
bottomPin?.priority = .defaultLow
|
bottomPin?.priority = .defaultLow
|
||||||
bottomPin?.isActive = true
|
bottomPin?.isActive = true
|
||||||
|
|
||||||
pagingView.setNumberOfPages(numberOfPages)
|
pagingView.numberOfPages = numberOfPages
|
||||||
(pagingView as? MVMCoreUIViewConstrainingProtocol)?.alignHorizontal?(.fill)
|
(pagingView as? MVMCoreUIViewConstrainingProtocol)?.alignHorizontal?(.fill)
|
||||||
pagingView.setPagingTouch { [weak self] (pager) in
|
pageIndex = pagingView.currentIndex
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
pagingView.indicatorTouchAction = { [weak self] pager in
|
||||||
guard let localSelf = self else {
|
DispatchQueue.main.async {
|
||||||
return
|
guard let self = self else { return }
|
||||||
}
|
let currentPage = pager.currentIndex
|
||||||
let currentPage = pager.currentPage()
|
self.pageIndex = currentPage
|
||||||
localSelf.pageIndex = currentPage
|
self.updateModelIndex()
|
||||||
localSelf.updateModelIndex()
|
self.goTo(self.currentIndex, animated: !UIAccessibility.isVoiceOverRunning)
|
||||||
localSelf.goTo(localSelf.currentIndex, animated: !UIAccessibility.isVoiceOverRunning)
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pagingView = pagingView
|
self.pagingView = pagingView
|
||||||
}
|
}
|
||||||
|
|
||||||
open func showPeaking(_ peaking: Bool) {
|
open func showPeaking(_ peaking: Bool) {
|
||||||
|
|
||||||
if peaking && !UIAccessibility.isVoiceOverRunning {
|
if peaking && !UIAccessibility.isVoiceOverRunning {
|
||||||
// Show overlay and arrow in peaking Cell
|
// Show overlay and arrow in peaking Cell
|
||||||
let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row }
|
let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row }
|
||||||
|
|
||||||
if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex {
|
if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex {
|
||||||
(collectionView.cellForItem(at: firstItem) as? CarouselItem)?.setPeaking(true, animated: true)
|
(collectionView.cellForItem(at: firstItem) as? CarouselItem)?.setPeaking(true, animated: true)
|
||||||
}
|
}
|
||||||
@ -245,9 +276,8 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) {
|
public func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) {
|
||||||
guard let cell = cell else {
|
guard let cell = cell else { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
if index == currentIndex {
|
if index == currentIndex {
|
||||||
cell.accessibilityElementsHidden = false
|
cell.accessibilityElementsHidden = false
|
||||||
var array = cell.accessibilityElements
|
var array = cell.accessibilityElements
|
||||||
@ -260,7 +290,7 @@ open class Carousel: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.accessibilityElements = array
|
accessibilityElements = array
|
||||||
} else {
|
} else {
|
||||||
cell.accessibilityElementsHidden = true
|
cell.accessibilityElementsHidden = true
|
||||||
}
|
}
|
||||||
@ -285,9 +315,9 @@ extension Carousel: UICollectionViewDataSource {
|
|||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
guard let molecule = molecules?[indexPath.row],
|
guard let molecule = molecules?[indexPath.row],
|
||||||
let moleculeInfo = getMoleculeInfo(with: molecule, delegateObject: nil) else {
|
let moleculeInfo = getMoleculeInfo(with: molecule, delegateObject: nil)
|
||||||
return UICollectionViewCell()
|
else { return UICollectionViewCell() }
|
||||||
}
|
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath)
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath)
|
||||||
if let protocolCell = cell as? MoleculeViewProtocol {
|
if let protocolCell = cell as? MoleculeViewProtocol {
|
||||||
protocolCell.reset()
|
protocolCell.reset()
|
||||||
@ -302,6 +332,7 @@ extension Carousel: UICollectionViewDataSource {
|
|||||||
extension Carousel: UIScrollViewDelegate {
|
extension Carousel: UIScrollViewDelegate {
|
||||||
|
|
||||||
func goTo(_ index: Int, animated: Bool) {
|
func goTo(_ index: Int, animated: Bool) {
|
||||||
|
|
||||||
showPeaking(false)
|
showPeaking(false)
|
||||||
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index)
|
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index)
|
||||||
currentIndex = index
|
currentIndex = index
|
||||||
@ -317,12 +348,12 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
guard loop else { return }
|
guard loop else { return }
|
||||||
|
|
||||||
let lastPageIndex = numberOfPages + 1
|
let lastPageIndex = numberOfPages + 1
|
||||||
let goToIndex = {(index: Int) in
|
let goToIndex = { (index: Int) in
|
||||||
self.goTo(index, animated: false)
|
self.goTo(index, animated: false)
|
||||||
self.collectionView.layoutIfNeeded()
|
self.collectionView.layoutIfNeeded()
|
||||||
self.pagingView?.setPage(self.pageIndex)
|
self.pagingView?.currentIndex = self.pageIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentIndex < 2 {
|
if currentIndex < 2 {
|
||||||
// If on a "buffer" last row (which is the first index), go to the real last row secretly. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking.
|
// If on a "buffer" last row (which is the first index), go to the real last row secretly. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking.
|
||||||
goToIndex(lastPageIndex)
|
goToIndex(lastPageIndex)
|
||||||
@ -333,14 +364,15 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkForDraggingOutOfBounds(_ scrollView: UIScrollView) {
|
func checkForDraggingOutOfBounds(_ scrollView: UIScrollView) {
|
||||||
guard loop, dragging else {
|
|
||||||
return
|
guard loop, dragging else { return }
|
||||||
}
|
|
||||||
// Checks if the user is not paging but attempting to drag endlessly and goes out of bounds. Caps the index.
|
// Checks if the user is not paging but attempting to drag endlessly and goes out of bounds. Caps the index.
|
||||||
if let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing {
|
if let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing {
|
||||||
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)
|
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)
|
||||||
let index = scrollView.contentOffset.x / (itemWidth + separatorWidth)
|
let index = scrollView.contentOffset.x / (itemWidth + separatorWidth)
|
||||||
let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1
|
let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1
|
||||||
|
|
||||||
if index < 1 {
|
if index < 1 {
|
||||||
currentIndex = 0
|
currentIndex = 0
|
||||||
updateModelIndex()
|
updateModelIndex()
|
||||||
@ -359,15 +391,17 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
//checkForDraggingOutOfBounds(scrollView)
|
//checkForDraggingOutOfBounds(scrollView)
|
||||||
|
|
||||||
// Let the pager know our progress if needed.
|
// Let the pager know our progress if needed.
|
||||||
pagingView?.scrollViewDidScroll?(collectionView)
|
pagingView?.scrollViewDidScroll(collectionView)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||||
|
|
||||||
dragging = true
|
dragging = true
|
||||||
showPeaking(false)
|
showPeaking(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||||
|
|
||||||
dragging = false
|
dragging = false
|
||||||
targetContentOffset.pointee = scrollView.contentOffset
|
targetContentOffset.pointee = scrollView.contentOffset
|
||||||
|
|
||||||
@ -376,11 +410,13 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
|
|
||||||
// We switch cards if we pass the velocity threshold or position threshold (currently 50%).
|
// We switch cards if we pass the velocity threshold or position threshold (currently 50%).
|
||||||
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)
|
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)
|
||||||
var cellToSwipeTo = Int(scrollView.contentOffset.x/(itemWidth + separatorWidth) + 0.5)
|
var cellToSwipeTo = Int(scrollView.contentOffset.x / (itemWidth + separatorWidth) + 0.5)
|
||||||
let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1
|
let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1
|
||||||
let velocityThreshold: CGFloat = 1.1
|
let velocityThreshold: CGFloat = 1.1
|
||||||
|
|
||||||
if velocity.x > velocityThreshold {
|
if velocity.x > velocityThreshold {
|
||||||
cellToSwipeTo = currentIndex + 1
|
cellToSwipeTo = currentIndex + 1
|
||||||
|
|
||||||
} else if velocity.x < -velocityThreshold {
|
} else if velocity.x < -velocityThreshold {
|
||||||
cellToSwipeTo = currentIndex - 1
|
cellToSwipeTo = currentIndex - 1
|
||||||
}
|
}
|
||||||
@ -393,9 +429,7 @@ extension Carousel: UIScrollViewDelegate {
|
|||||||
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
||||||
// Cycle to other end if on buffer cell.
|
// Cycle to other end if on buffer cell.
|
||||||
handleUserOnBufferCell()
|
handleUserOnBufferCell()
|
||||||
|
pagingView?.currentIndex = pageIndex
|
||||||
pagingView?.setPage(pageIndex)
|
|
||||||
|
|
||||||
showPeaking(true)
|
showPeaking(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,16 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
@objcMembers public class CarouselModel: MoleculeModelProtocol {
|
@objcMembers public class CarouselModel: MoleculeModelProtocol {
|
||||||
public static var identifier: String = "carousel"
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public static var identifier: String {
|
||||||
|
return "carousel"
|
||||||
|
}
|
||||||
|
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public var molecules: [CarouselItemModel]
|
public var molecules: [CarouselItemModel]
|
||||||
public var index: Int = 0
|
public var index: Int = 0
|
||||||
@ -21,11 +29,15 @@ import UIKit
|
|||||||
public var itemAlignment: UICollectionView.ScrollPosition?
|
public var itemAlignment: UICollectionView.ScrollPosition?
|
||||||
public var pagingMolecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)?
|
public var pagingMolecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)?
|
||||||
|
|
||||||
public init(molecules: [CarouselItemModel]){
|
public init(molecules: [CarouselItemModel]) {
|
||||||
self.molecules = molecules
|
self.molecules = molecules
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case backgroundColor
|
||||||
case molecules
|
case molecules
|
||||||
@ -37,9 +49,13 @@ import UIKit
|
|||||||
case itemWidthPercent
|
case itemWidthPercent
|
||||||
case itemAlignment
|
case itemAlignment
|
||||||
case pagingMolecule
|
case pagingMolecule
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codec
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules)
|
molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules)
|
||||||
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
|
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
|
||||||
@ -65,5 +81,5 @@ import UIKit
|
|||||||
try container.encode(itemWidthPercent, forKey: .itemWidthPercent)
|
try container.encode(itemWidthPercent, forKey: .itemWidthPercent)
|
||||||
try container.encode(itemAlignment, forKey: .itemAlignment)
|
try container.encode(itemAlignment, forKey: .itemAlignment)
|
||||||
try container.encodeModelIfPresent(pagingMolecule, forKey: .pagingMolecule)
|
try container.encodeModelIfPresent(pagingMolecule, forKey: .pagingMolecule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ extension MoleculeViewProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing, optionals.
|
// Do nothing, optionals.
|
||||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {}
|
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {}
|
||||||
public func reset() {}
|
public func reset() {}
|
||||||
|
|
||||||
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
|
|||||||
99
MVMCoreUI/BaseClasses/ImageView.swift
Normal file
99
MVMCoreUI/BaseClasses/ImageView.swift
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
//
|
||||||
|
// ImageView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/13/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
open class ImageView: UIImageView, ModelMoleculeViewProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open var model: MoleculeModelProtocol?
|
||||||
|
|
||||||
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initialization
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
initialSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(image: UIImage?) {
|
||||||
|
super.init(image: image)
|
||||||
|
initialSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
public convenience init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
initialSetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public func initialSetup() {
|
||||||
|
if !initialSetupPerformed {
|
||||||
|
initialSetupPerformed = true
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - ModelMoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||||
|
self.model = model
|
||||||
|
if let backgroundColor = model?.backgroundColor {
|
||||||
|
self.backgroundColor = backgroundColor.uiColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class func nameForReuse(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
|
return model?.moleculeName
|
||||||
|
}
|
||||||
|
|
||||||
|
open class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
open class func requiredModules(_ molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK:- MVMCoreViewProtocol
|
||||||
|
extension ImageView: MVMCoreViewProtocol {
|
||||||
|
|
||||||
|
open func updateView(_ size: CGFloat) { }
|
||||||
|
|
||||||
|
/// Will be called only once.
|
||||||
|
open func setupView() {
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
insetsLayoutMarginsFromSafeArea = false
|
||||||
|
MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK:- MVMCoreUIMoleculeViewProtocol
|
||||||
|
extension ImageView: MVMCoreUIMoleculeViewProtocol {
|
||||||
|
|
||||||
|
open func reset() {
|
||||||
|
backgroundColor = .clear
|
||||||
|
}
|
||||||
|
|
||||||
|
open func setAsMolecule() { }
|
||||||
|
}
|
||||||
@ -81,6 +81,7 @@ open class TextViewModel: TextEntryFieldModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
public override func encode(to encoder: Encoder) throws {
|
||||||
|
try super.encode(to: encoder)
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||||
try container.encodeIfPresent(height, forKey: .height)
|
try container.encodeIfPresent(height, forKey: .height)
|
||||||
|
|||||||
@ -8,11 +8,16 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class View: UIView, MoleculeViewProtocol {
|
@objcMembers open class View: UIView, MoleculeViewProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open var model: MoleculeModelProtocol?
|
open var model: MoleculeModelProtocol?
|
||||||
|
|
||||||
private var initialSetupPerformed = false
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -21,7 +26,7 @@ import UIKit
|
|||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
initialSetup()
|
initialSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
}
|
}
|
||||||
@ -38,12 +43,15 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:- MoleculeViewProtocol
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
self.model = model
|
self.model = model
|
||||||
if let backgroundColor = model.backgroundColor {
|
if let backgroundColor = model.backgroundColor {
|
||||||
self.backgroundColor = backgroundColor.uiColor
|
self.backgroundColor = backgroundColor.uiColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||||
@ -66,8 +74,8 @@ import UIKit
|
|||||||
// MARK:- MVMCoreViewProtocol
|
// MARK:- MVMCoreViewProtocol
|
||||||
extension View: MVMCoreViewProtocol {
|
extension View: MVMCoreViewProtocol {
|
||||||
|
|
||||||
open func updateView(_ size: CGFloat) {}
|
open func updateView(_ size: CGFloat) { }
|
||||||
|
|
||||||
/// Will be called only once.
|
/// Will be called only once.
|
||||||
open func setupView() {
|
open func setupView() {
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|||||||
@ -68,8 +68,8 @@
|
|||||||
|
|
||||||
|
|
||||||
// MARK: Carousel
|
// MARK: Carousel
|
||||||
"MVMCoreUIPageControl_currentpage_index" = "page %ld of %ld";
|
"MVMCoreUIPageControl_currentpage_index" = "page %@ of %d";
|
||||||
"MVMCoreUIPageControlslides_currentpage_index" = "slide %ld of %ld";
|
"MVMCoreUIPageControlslides_currentpage_index" = "slide %@ of %d";
|
||||||
|
|
||||||
|
|
||||||
// MARK: Styler
|
// MARK: Styler
|
||||||
|
|||||||
@ -48,8 +48,8 @@
|
|||||||
"AccOff" = "apagado";
|
"AccOff" = "apagado";
|
||||||
"AccToggleHint" = "toca dos veces para alternar";
|
"AccToggleHint" = "toca dos veces para alternar";
|
||||||
// Carousel
|
// Carousel
|
||||||
"MVMCoreUIPageControl_currentpage_index" = "página %ld de %ld";
|
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
|
||||||
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %ld of %ld";
|
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";
|
||||||
//Styler
|
//Styler
|
||||||
"CountDownDay" = " día";
|
"CountDownDay" = " día";
|
||||||
"CountDownHour" = " hora";
|
"CountDownHour" = " hora";
|
||||||
|
|||||||
@ -50,8 +50,8 @@
|
|||||||
"AccOff" = "apagado";
|
"AccOff" = "apagado";
|
||||||
"AccToggleHint" = "toca dos veces para alternar";
|
"AccToggleHint" = "toca dos veces para alternar";
|
||||||
// Carousel
|
// Carousel
|
||||||
"MVMCoreUIPageControl_currentpage_index" = "página %ld de %ld";
|
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
|
||||||
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %ld of %ld";
|
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";
|
||||||
//Styler
|
//Styler
|
||||||
"CountDownDay" = " día";
|
"CountDownDay" = " día";
|
||||||
"CountDownHour" = " hora";
|
"CountDownHour" = " hora";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user