├── .circleci └── config.yml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── PrepareRelaseVersionForDelivery.yml │ ├── PrepareSimulatorVersionForDelivery.yml │ ├── Test.yml │ └── TestFrameworks.yml ├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Content ├── CustomViewModels.md └── Images │ ├── ListGridGallery.png │ ├── LiveCoding.png │ ├── Logo.png │ ├── Project.png │ └── XCodeTemplate.png ├── DSKitExplorer ├── DSKitExplorer.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcshareddata │ │ └── xcschemes │ │ └── DSKitExplorer.xcscheme └── DSKitExplorer │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── Add Frameworks.imageset │ │ ├── Add Frameworks.png │ │ └── Contents.json │ ├── AllApps-demo.imageset │ │ ├── AllApps-demo.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon-Spotlight-40.png │ │ ├── Icon-Spotlight-40@2x.png │ │ ├── Icon-Spotlight-40@3x.png │ │ └── Icon.png │ ├── Contents.json │ ├── Copy items if need.imageset │ │ ├── Contents.json │ │ └── Copy items if need.png │ ├── CoverAppearance.imageset │ │ ├── Contents.json │ │ └── CoverAppearance.jpg │ ├── CoverCodeExampleHome.imageset │ │ ├── Contents.json │ │ └── CoverCodeExample.jpg │ ├── CoverGetStarted.imageset │ │ ├── Contents.json │ │ └── CoverGetStarted.jpg │ ├── CoverLayout.imageset │ │ ├── Contents.json │ │ └── CoverLayout.jpg │ ├── Embed frameworks.imageset │ │ ├── Contents.json │ │ └── Embed frameworks.png │ ├── Home.imageset │ │ ├── Contents.json │ │ └── Home.png │ ├── Icon.imageset │ │ ├── Contents.json │ │ └── Icon.png │ ├── LayoutExample.imageset │ │ ├── Contents.json │ │ └── LayoutExample.png │ ├── LightDarkModes.imageset │ │ ├── Contents.json │ │ └── LightDarkModes.png │ ├── Welcome.imageset │ │ ├── Contents.json │ │ └── DSKit_home.png │ ├── barbershop.imageset │ │ ├── Contents.json │ │ └── barbershop.jpg │ ├── beautysaloon.imageset │ │ ├── Contents.json │ │ ├── Screen Shot 2021-03-09 at 10.jpg │ │ └── beautysaloon.png │ ├── dskitIcon.imageset │ │ ├── Contents.json │ │ └── dskitIcon.pdf │ ├── ecommerce.imageset │ │ ├── Contents.json │ │ └── ecommerce.jpg │ ├── facebook.imageset │ │ ├── Contents.json │ │ └── facebook.pdf │ ├── flowerstore.imageset │ │ ├── Contents.json │ │ ├── flowerstore-1.jpg │ │ └── flowerstore_light.jpg │ ├── foodDelivery.imageset │ │ ├── Contents.json │ │ └── pexels-photo-1600711.jpeg │ ├── glasses.imageset │ │ ├── Contents.json │ │ └── glasses.jpg │ ├── grocerystore.imageset │ │ ├── Contents.json │ │ ├── grocerystore.jpg │ │ └── grocerystore_dark.jpg │ ├── instagram.imageset │ │ ├── Contents.json │ │ └── instagram.pdf │ ├── picture-1.imageset │ │ ├── Contents.json │ │ └── picture-1.jpg │ ├── picture-10.imageset │ │ ├── Contents.json │ │ └── picture-10.jpg │ ├── picture-11.imageset │ │ ├── Contents.json │ │ └── picture-11.jpg │ ├── picture-12.imageset │ │ ├── Contents.json │ │ └── picture-12.jpg │ ├── picture-13.imageset │ │ ├── Contents.json │ │ └── picture-13.jpg │ ├── picture-2.imageset │ │ ├── Contents.json │ │ └── picture-2.jpg │ ├── picture-3.imageset │ │ ├── Contents.json │ │ └── picture-3.jpg │ ├── picture-4.imageset │ │ ├── Contents.json │ │ └── picture-4.jpg │ ├── picture-5.imageset │ │ ├── Contents.json │ │ └── picture-5.jpg │ ├── picture-6.imageset │ │ ├── Contents.json │ │ └── picture-6.jpg │ ├── picture-7.imageset │ │ ├── Contents.json │ │ └── picture-7.jpg │ ├── picture-8.imageset │ │ ├── Contents.json │ │ └── picture-8.jpg │ ├── picture-9.imageset │ │ ├── Contents.json │ │ └── picture-9.jpg │ ├── twitter.imageset │ │ ├── Contents.json │ │ └── twitter.pdf │ └── visa-card-bg.imageset │ │ ├── Contents.json │ │ └── visa-card-bg.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── CustomViewModels │ └── Code │ │ ├── DSCodeUIView.swift │ │ ├── DSCodeUIView.xib │ │ └── DSCodeVM.swift │ ├── Documentation │ ├── Layout │ │ ├── Gallery │ │ │ ├── GalleryAbsoluteWidthLayoutVC.swift │ │ │ ├── GalleryFractional1GroupedLayoutVC.swift │ │ │ ├── GalleryFractional1LayoutVC.swift │ │ │ ├── GalleryFractionalWidthLayoutVC.swift │ │ │ ├── GalleryFullWidthLayoutVC.swift │ │ │ ├── GalleryLayoutViewController.swift │ │ │ ├── GalleryPageControlFractional1LayoutVC.swift │ │ │ ├── GalleryPageControlLayoutVC.swift │ │ │ └── GalleryWithSupplementaryItemsLayoutVC.swift │ │ ├── Grid │ │ │ ├── GridGrouped3RowsLayoutVC.swift │ │ │ ├── GridGrouped5RowsHeaderFooterLayoutVC.swift │ │ │ ├── GridLayoutViewController.swift │ │ │ ├── GridSimpleHeaderFooterLayoutVC.swift │ │ │ ├── GridSimpleLayoutVC.swift │ │ │ └── GridWithSupplementaryItemsLayoutVC.swift │ │ └── Lists │ │ │ ├── ListGroupedAndSeparatorLayoutVC.swift │ │ │ ├── ListGroupedLayoutVC.swift │ │ │ ├── ListGroupedSeparatorHeaderFooterLayoutVC.swift │ │ │ ├── ListLayoutViewController.swift │ │ │ ├── ListSeparatorLayoutVC.swift │ │ │ ├── ListSimpleLayoutVC.swift │ │ │ ├── ListWithAdditionalViewModelsLayoutVC.swift │ │ │ └── ListWithSupplementaryItemsLayoutVC.swift │ ├── Show │ │ ├── ShowBottomContentVC.md │ │ ├── ShowBottomContentVC.swift │ │ ├── ShowContentVC.md │ │ ├── ShowContentVC.swift │ │ ├── ShowContentViewController.swift │ │ ├── ShowTopBottomContentVC.md │ │ ├── ShowTopBottomContentVC.swift │ │ ├── ShowTopContentVC.md │ │ └── ShowTopContentVC.swift │ ├── SourceCodeViewController.swift │ ├── Style │ │ ├── StyleVC.md │ │ ├── StyleVC.swift │ │ └── StyleViewController.swift │ ├── Typography │ │ ├── TypographyActiveTextVC.swift │ │ ├── TypographyHtmlVC.md │ │ ├── TypographyTextComposerActionVC.swift │ │ ├── TypographyTextComposerTextVC.swift │ │ ├── TypographyTextGalleryVC.swift │ │ ├── TypographyTextGridVC.swift │ │ ├── TypographyTextListVC.swift │ │ ├── TypographyTextTypesVC.md │ │ ├── TypographyTextTypesVC.swift │ │ └── TypographyViewController.swift │ ├── ViewModels │ │ ├── Actions │ │ │ ├── ActionGalleryVC.swift │ │ │ ├── ActionGridVC.swift │ │ │ ├── ActionGroupedListVC.swift │ │ │ ├── ActionLeftIconVC.swift │ │ │ ├── ActionLeftImageVC.swift │ │ │ ├── ActionLeftRoundImageSizeVC.swift │ │ │ ├── ActionLeftRoundImageVC.swift │ │ │ ├── ActionListVC.swift │ │ │ ├── ActionRightButtonVC.swift │ │ │ ├── ActionRightIconVC.swift │ │ │ ├── ActionRightImageVC.swift │ │ │ ├── ActionRightRoundImageSizeVC.swift │ │ │ ├── ActionRightRoundImageVC.swift │ │ │ ├── ActionTopImageVC.swift │ │ │ └── ActionViewController.swift │ │ ├── Buttons │ │ │ ├── ButtonGalleryVC.swift │ │ │ ├── ButtonGridVC.swift │ │ │ ├── ButtonListVC.swift │ │ │ ├── ButtonViewController.swift │ │ │ └── ButtonsVC.swift │ │ ├── Cards │ │ │ └── CardViewController.swift │ │ ├── Images │ │ │ ├── ImageGalleryHandleDidTapVC.swift │ │ │ ├── ImageGalleryVC.swift │ │ │ ├── ImageGridVC.swift │ │ │ ├── ImageListVC.swift │ │ │ ├── ImageViewController.swift │ │ │ └── ImagesVC.swift │ │ ├── Maps │ │ │ └── MapViewController.swift │ │ ├── Page │ │ │ ├── PageSimplePageVC.swift │ │ │ ├── PageSimplePageWithInsetsVC.swift │ │ │ └── PageViewController.swift │ │ ├── PageControl │ │ │ └── PageControlViewController.swift │ │ ├── QuantityPicker │ │ │ ├── QuantityPickerVC.swift │ │ │ └── QuantityPickerViewController.swift │ │ ├── Segments │ │ │ └── SegmentViewController.swift │ │ ├── TextFields │ │ │ ├── TextFieldBuiltInValidationVC.md │ │ │ ├── TextFieldBuiltInValidationVC.swift │ │ │ ├── TextFieldCustomInvalidPlaceHolderMessageVC.md │ │ │ ├── TextFieldCustomInvalidPlaceHolderMessageVC.swift │ │ │ ├── TextFieldCustomValidationVC.md │ │ │ ├── TextFieldCustomValidationVC.swift │ │ │ ├── TextFieldIconsVC.md │ │ │ ├── TextFieldIconsVC.swift │ │ │ ├── TextFieldInvalidDataVC.md │ │ │ ├── TextFieldInvalidDataVC.swift │ │ │ ├── TextFieldShortcutsVC.md │ │ │ ├── TextFieldShortcutsVC.swift │ │ │ ├── TextFieldValidDataVC.md │ │ │ ├── TextFieldValidDataVC.swift │ │ │ ├── TextFieldViewController.swift │ │ │ ├── TextFieldsGridVC.md │ │ │ ├── TextFieldsGridVC.swift │ │ │ ├── TextFieldsGroupedGridVC.md │ │ │ ├── TextFieldsGroupedGridVC.swift │ │ │ ├── TextFieldsGroupedVC.md │ │ │ ├── TextFieldsGroupedVC.swift │ │ │ ├── TextFieldsVC.md │ │ │ └── TextFieldsVC.swift │ │ └── TextView │ │ │ ├── TextViewSimpleVC.swift │ │ │ └── TextViewViewController.swift │ └── WebsiteGenerator │ │ ├── Documentable.swift │ │ ├── DocumentsGroup.swift │ │ ├── DocumentsGroups+Sections.swift │ │ └── DocumentsGroups.swift │ ├── Extensions │ ├── DSActionVM+SourceCode.swift │ ├── DSTextVM+Description.swift │ ├── DSViewController+PoweredBy.swift │ ├── DSViewController+SourceCode.swift │ └── DSViewController+ViewModels.swift │ ├── Info.plist │ ├── SceneDelegate.swift │ └── ViewController.swift ├── Gemfile.lock ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── DSKit │ ├── Appearance │ │ ├── Colors │ │ │ ├── ColorSpaces.swift │ │ │ ├── DSColor.swift │ │ │ ├── DSColorScheme+Color.swift │ │ │ └── UIColorExtension.swift │ │ ├── DSAppearance.swift │ │ ├── DSKitAppearance.swift │ │ ├── DSNewsAppearance.swift │ │ ├── Designable │ │ │ ├── DSDesignable.swift │ │ │ ├── DSDesignableButtonColor.swift │ │ │ ├── DSDesignableFonts.swift │ │ │ ├── DSDesignableNavigationBarColor.swift │ │ │ ├── DSDesignablePriceColor.swift │ │ │ ├── DSDesignableTabbarColor.swift │ │ │ ├── DSDesignableTextColor.swift │ │ │ ├── DSDesignableTextFieldColor.swift │ │ │ ├── DSDesignableViewColors.swift │ │ │ └── DSDesignableViewController.swift │ │ ├── Fonts │ │ │ ├── DSScaledFont.swift │ │ │ ├── HoeflerText.plist │ │ │ └── Noteworthy.plist │ │ ├── MintAppearance.swift │ │ ├── SystemAppearance.swift │ │ └── UIColor+String.swift │ ├── CollectionView │ │ ├── DSCollectionView.swift │ │ ├── DSCollectionViewPosition.swift │ │ ├── Data │ │ │ ├── DSCollectionView+DataSource.swift │ │ │ └── DSCollectionView+SuplimentaryViewDataSource.swift │ │ ├── Helpers │ │ │ ├── DSCollectionView+AdditionalSpace.swift │ │ │ ├── DSCollectionView+Config.swift │ │ │ ├── DSCollectionView+Forms.swift │ │ │ ├── DSCollectionView+Identifiers.swift │ │ │ ├── DSCollectionView+Keyboard.swift │ │ │ ├── DSCollectionView+Register.swift │ │ │ ├── DSCollectionView+Reload.swift │ │ │ └── DSCollectionView+Show.swift │ │ └── Layout │ │ │ ├── DSCollectionView+GalleryLayout.swift │ │ │ ├── DSCollectionView+GridLayout.swift │ │ │ ├── DSCollectionView+Layout.swift │ │ │ ├── DSCollectionView+ListLayout.swift │ │ │ └── DSCollectionView+SupplementaryViewLayout.swift │ ├── ContentModels │ │ ├── Button │ │ │ └── DSButton.swift │ │ ├── Image │ │ │ ├── DSImage+DSViewable.swift │ │ │ ├── DSImage.swift │ │ │ ├── DSImageContent.swift │ │ │ ├── DSImageContentMode.swift │ │ │ ├── DSImageDisplayStyle.swift │ │ │ ├── DSImageHeight.swift │ │ │ ├── DSImageSize.swift │ │ │ └── DSImageTintColor.swift │ │ ├── Price │ │ │ ├── DSPrice+Random.swift │ │ │ ├── DSPrice+Viewable.swift │ │ │ └── DSPrice.swift │ │ ├── Text │ │ │ ├── DSTextColor.swift │ │ │ ├── DSTextComposer+Add.swift │ │ │ ├── DSTextComposer+AttributedString.swift │ │ │ ├── DSTextComposer+DSViewable.swift │ │ │ ├── DSTextComposer+ViewModels.swift │ │ │ ├── DSTextComposer.swift │ │ │ ├── DSTextFont.swift │ │ │ ├── DSTextParagraph.swift │ │ │ ├── DSTextParagraphType.swift │ │ │ └── DSTextType.swift │ │ └── View │ │ │ ├── DSView.swift │ │ │ └── DSViewPosition.swift │ ├── Extensions │ │ ├── CGFloat+UIEdgeInsets.swift │ │ ├── Double+Rounded.swift │ │ ├── Int+Cents.swift │ │ ├── Int+Plural.swift │ │ ├── Int+TimeString.swift │ │ ├── NSAttributedString+Badge.swift │ │ ├── NSAttributedString+Size.swift │ │ ├── NSNumber+Cents.swift │ │ ├── Notification+FrameAndDuration.swift │ │ ├── String+Amount.swift │ │ ├── String+AppName.swift │ │ ├── String+Currency.swift │ │ ├── String+EstimatedHeight.swift │ │ ├── String+OpenURL.swift │ │ ├── String+Random.swift │ │ ├── String+Size.swift │ │ ├── UIApplication+KeyWindow.swift │ │ ├── UIApplication+TopViewController.swift │ │ ├── UIButton+Colors.swift │ │ ├── UIButton+EdgeInsets.swift │ │ ├── UIColor+Equtable.swift │ │ ├── UIColor+IsLight.swift │ │ ├── UIDeviceExtension.swift │ │ ├── UIEdgeInsets+Add.swift │ │ ├── UIEdgeInsets+NSDirectionalEdgeInsets.swift │ │ ├── UIEdgeInsetsExtension.swift │ │ ├── UIImage+AverageColor.swift │ │ ├── UIImage+ResizeCrop.swift │ │ ├── UIImage+SFSymbol.swift │ │ ├── UIImageViewExtension.swift │ │ ├── UILabelExtension.swift │ │ ├── UIPageControl+Appearance.swift │ │ ├── UIView+Border.swift │ │ ├── UIView+Bounce.swift │ │ ├── UIView+Constraints.swift │ │ ├── UIView+Corners.swift │ │ ├── UIView+DSViewModelDisplayStyle.swift │ │ ├── UIView+EdgeInsets.swift │ │ └── UIViewExtension.swift │ ├── Helpers │ │ ├── AmountFormatter.swift │ │ ├── DSMaterialSpinner.swift │ │ ├── DSMessageHUD.swift │ │ ├── DSSFSymbolConfig.swift │ │ ├── Date+StringFormatting.swift │ │ ├── DispatchQueue.swift │ │ ├── IAKCacheManager.swift │ │ ├── NonEquatable.swift │ │ ├── PasswordValidator.swift │ │ ├── PreviewContainer.swift │ │ ├── ProgressHUD.swift │ │ ├── Rescale.swift │ │ ├── URLOpener.swift │ │ └── Validator.swift │ ├── Images.xcassets │ │ ├── Contents.json │ │ ├── mapPlaceholder.imageset │ │ │ ├── Contents.json │ │ │ └── mapPlaceholder.pdf │ │ └── placeholder.imageset │ │ │ ├── Contents.json │ │ │ └── placeholder.pdf │ ├── ReusableCollectionViewCells │ │ ├── DSReusableCollectionSupplementaryView.swift │ │ ├── DSReusableCollectionViewCell+SupplementaryViews.swift │ │ ├── DSReusableCollectionViewCell.swift │ │ ├── DSReusableCollectionViewsHeightManager.swift │ │ └── UIView+LayoutAttributes.swift │ ├── Sections │ │ ├── DSDiffableSection.swift │ │ ├── DSGallerySection.swift │ │ ├── DSGridSection.swift │ │ ├── DSListSection.swift │ │ ├── DSSection+Count.swift │ │ ├── DSSection+DisplayStyle.swift │ │ ├── DSSection+Footer.swift │ │ ├── DSSection+Hash.swift │ │ ├── DSSection+Header.swift │ │ ├── DSSection+Identifiers.swift │ │ ├── DSSection+Insets.swift │ │ ├── DSSection+Width.swift │ │ ├── DSSection.swift │ │ ├── DSSectionBackgroundColorPrimaryDecorationView.swift │ │ ├── DSSectionBackgroundColorSecondaryDecorationView.swift │ │ ├── DSSectionBackgroundDecorationView.swift │ │ ├── DSSectionBackgroundType.swift │ │ ├── DSSectionGalleryType.swift │ │ └── DSSectionType.swift │ ├── ViewControllers │ │ ├── BaseViewController │ │ │ ├── DSBaseViewController+Loading.swift │ │ │ ├── DSBaseViewController+MessageHUD.swift │ │ │ ├── DSBaseViewController+NavigationStyle.swift │ │ │ └── DSBaseViewController.swift │ │ ├── DSCollectionViewController │ │ │ ├── DSCollectionViewController+BottomContent.swift │ │ │ ├── DSCollectionViewController+Shadows.swift │ │ │ ├── DSCollectionViewController+TopContent.swift │ │ │ └── DSCollectionViewController.swift │ │ ├── DSNavigationViewController │ │ │ └── DSNavigationViewController.swift │ │ ├── DSViewController │ │ │ ├── DSViewController+DecorationIcon.swift │ │ │ ├── DSViewController+Forms.swift │ │ │ ├── DSViewController+Placeholder.swift │ │ │ ├── DSViewController+ShowBottomContent.swift │ │ │ ├── DSViewController+ShowContent.swift │ │ │ ├── DSViewController+ShowTopContent.swift │ │ │ └── DSViewController.swift │ │ └── TabBarViewController │ │ │ └── DSTabBarViewController.swift │ ├── ViewModelProtocol │ │ ├── DSPageControlable.swift │ │ ├── DSReusableUIView.swift │ │ ├── DSSideView.swift │ │ ├── DSSupplementaryView.swift │ │ ├── DSViewModel.swift │ │ ├── DSViewModelBorderStyle.swift │ │ ├── DSViewModelColorStyle.swift │ │ ├── DSViewModelCornersStyle.swift │ │ ├── DSViewModelDataSource.swift │ │ ├── DSViewModelDisplayStyle.swift │ │ ├── DSViewModelHeight.swift │ │ ├── DSViewModelShadowStyle.swift │ │ ├── DSViewModelStyle.swift │ │ ├── DSViewModelWidth.swift │ │ ├── DefaultReusableUIViewView.swift │ │ └── Extensions │ │ │ ├── DSViewModel+Default.swift │ │ │ ├── DSViewModel+PrepareToDisplay.swift │ │ │ ├── DSViewModel+Sections.swift │ │ │ ├── DSViewModel+SideViews.swift │ │ │ ├── DSViewModel+ViewColors.swift │ │ │ ├── DSViewModel+didTap.swift │ │ │ ├── DSViewModel+isEqual.swift │ │ │ └── DSViewModelDisplayStyle+UIEdgeInsets.swift │ └── ViewModels │ │ ├── Action │ │ ├── DSActionUIView.swift │ │ ├── DSActionUIView.xib │ │ ├── DSActionVM+LeftContent.swift │ │ ├── DSActionVM+RightContent.swift │ │ ├── DSActionVM+TopContent.swift │ │ └── DSActionVM.swift │ │ ├── ActiveText │ │ ├── DSActiveTextUIView.swift │ │ ├── DSActiveTextUIView.xib │ │ └── DSActiveTextVM.swift │ │ ├── Button │ │ ├── DSButtonUIView.swift │ │ ├── DSButtonUIView.xib │ │ ├── DSButtonVM.swift │ │ ├── ImoButton.swift │ │ └── ImoUIButton.swift │ │ ├── Card │ │ ├── DSCardUIView.swift │ │ ├── DSCardUIView.xib │ │ └── DSCardVM.swift │ │ ├── Color │ │ ├── DSColorUIView.swift │ │ ├── DSColorUIView.xib │ │ └── DSColorVM.swift │ │ ├── Image │ │ ├── DSImageUIView.swift │ │ ├── DSImageUIView.xib │ │ └── DSImageVM.swift │ │ ├── Label │ │ ├── DSLabelUIView.swift │ │ ├── DSLabelUIView.xib │ │ └── DSLabelVM.swift │ │ ├── Map │ │ ├── DSMapUIView.swift │ │ ├── DSMapUIView.xib │ │ └── DSMapVM.swift │ │ ├── Page │ │ ├── DSPageUIView.swift │ │ ├── DSPageUIView.xib │ │ └── DSPageVM.swift │ │ ├── PageControl │ │ ├── DSPageControlUIView.swift │ │ ├── DSPageControlUIView.xib │ │ └── DSPageControlViewModel.swift │ │ ├── QuantityPicker │ │ ├── DSQuantityPicker+RightContent.swift │ │ ├── DSQuantityPickerUIView.swift │ │ ├── DSQuantityPickerUIView.xib │ │ ├── DSQuantityPickerVM+LeftContent.swift │ │ └── DSQuantityPickerVM.swift │ │ ├── Segment │ │ ├── DSSegmentUIView.swift │ │ ├── DSSegmentUIView.xib │ │ └── DSSegmentViewModel.swift │ │ ├── Separator │ │ ├── DSSeparatorUIView.swift │ │ ├── DSSeparatorUIView.xib │ │ └── DSSeparatorVM.swift │ │ ├── Slider │ │ ├── DSSliderUIView.swift │ │ ├── DSSliderUIView.xib │ │ └── DSSliderVM.swift │ │ ├── Space │ │ ├── DSSpaceUIView.swift │ │ ├── DSSpaceUIView.xib │ │ └── DSSpaceVM.swift │ │ ├── Switch │ │ ├── DSSwitchUIView.swift │ │ ├── DSSwitchUIView.xib │ │ └── DSSwitchVM.swift │ │ ├── TextField │ │ ├── DSTextFieldUIView.swift │ │ ├── DSTextFieldUIView.xib │ │ ├── DSTextFieldVM+Shortcuts.swift │ │ ├── DSTextFieldVM+Validations.swift │ │ └── DSTextFieldVM.swift │ │ └── TextView │ │ ├── DSTextViewUIView.swift │ │ ├── DSTextViewUIView.xib │ │ └── DSTextViewVM.swift ├── DSKitCalendar │ ├── DSCalendarViewController.swift │ ├── DSDayLabel.swift │ ├── DSDayOfWeekLabel.swift │ ├── DSDayRangeIndicatorView.swift │ ├── DSMonthLabel.swift │ └── DSTooltipView.swift └── DSKitFakery │ ├── DSFaker.swift │ ├── Models │ ├── DSAddress.swift │ └── DSPerson.swift │ ├── URL+AdditionalProducts.swift │ ├── URL+Cards.swift │ ├── URL+Echeveria.swift │ ├── URL+Flowers.swift │ ├── URL+Gifts.swift │ ├── URL+Hydrangea.swift │ ├── URL+Jeans.swift │ ├── URL+Profile.swift │ ├── URL+Roses.swift │ ├── URL+Shirts.swift │ ├── URL+Shoes.swift │ ├── URL+Sneakers.swift │ ├── URL+TShirts.swift │ ├── URL+TopFlowers.swift │ ├── URL+Tulips.swift │ ├── URL+Watches.swift │ └── URLExtension.swift ├── Templates └── ViewModelTemplates │ ├── ViewModel.xctemplate │ ├── DS___FILEBASENAME___UIView.swift │ ├── DS___FILEBASENAME___UIView.xib │ ├── DS___FILEBASENAME___VM.swift │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ └── TemplateInfo.plist │ └── install.sh └── Tests └── DSKitTests └── DSKitTests.swift /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/PrepareRelaseVersionForDelivery.yml: -------------------------------------------------------------------------------- 1 | name: Archive Release version of DSKit 2 | on: 3 | push: 4 | paths: 5 | - 'DSKit/**' 6 | - 'DSKitFramework/**' 7 | - 'fastlane/**' 8 | jobs: 9 | test: 10 | runs-on: self-hosted 11 | if: "contains(github.event.head_commit.message, 'archive')" 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Build all frameworks, test, and archive 15 | run: fastlane prepareForDeliveryReleaseVersion 16 | - name: Upload report result 17 | continue-on-error: true 18 | uses: actions/upload-artifact@v2 19 | with: 20 | name: Release version of DSKit 21 | path: DSKitFramework 22 | -------------------------------------------------------------------------------- /.github/workflows/PrepareSimulatorVersionForDelivery.yml: -------------------------------------------------------------------------------- 1 | name: Archive Simulator version of DSKit 2 | on: 3 | push: 4 | paths: 5 | - 'DSKit/**' 6 | - 'DSKitFramework/**' 7 | - 'fastlane/**' 8 | jobs: 9 | test: 10 | runs-on: self-hosted 11 | if: "contains(github.event.head_commit.message, 'archive')" 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Build all frameworks, test, and archive 15 | run: fastlane prepareForDeliverySimulatorVersion 16 | - name: Upload report result 17 | continue-on-error: true 18 | uses: actions/upload-artifact@v2 19 | with: 20 | name: Simulator version of DSKit 21 | path: DSKitFramework 22 | -------------------------------------------------------------------------------- /.github/workflows/Test.yml: -------------------------------------------------------------------------------- 1 | name: Run DSKit Tests 2 | on: 3 | push: 4 | paths: 5 | - 'DSKit/**' 6 | - 'fastlane/**' 7 | jobs: 8 | test: 9 | runs-on: self-hosted 10 | if: "!contains(github.event.head_commit.message, 'skip ci')" 11 | steps: 12 | - uses: actions/checkout@v1 13 | - name: Test 14 | run: cd 'DSKit' && fastlane scan --device "iPhone 8" --scheme "DSKit Explorer" --clean 15 | -------------------------------------------------------------------------------- /.github/workflows/TestFrameworks.yml: -------------------------------------------------------------------------------- 1 | name: Run Frameworks Tests 2 | on: 3 | push: 4 | paths: 5 | - 'DSKit/**' 6 | - 'DSKitFramework/**' 7 | - 'fastlane/**' 8 | jobs: 9 | test: 10 | runs-on: self-hosted 11 | if: "!contains(github.event.head_commit.message, 'skip ci')" 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Build all frameworks for simulator and copy to DSKit Framework folder 15 | run: fastlane buildAllFrameworksForSimulatorAndCopyToDSKitFrameworkTestDSKitFrameworks 16 | 17 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | DSKit is developed completely in the open, and your contributions are more than welcome. 2 | 3 | Before you start using DSKit in any of your projects, it’s highly recommended that you spend a few minutes familiarizing yourself with its documentation and internal implementation, so that you’ll be ready to tackle any issues or edge cases that you might encounter. 4 | 5 | Since this is a very young project, it’s likely to have many limitations and missing features, which is something that can really only be discovered and addressed as more people start using it. 6 | 7 | This project does not come with GitHub Issues-based support, and users are instead encouraged to become active participants in its continued development — by fixing any bugs that they encounter, or by improving the documentation wherever it’s found to be lacking. 8 | 9 | If you wish to make a change, open a Pull Request — even if it just contains a draft of the changes you’re planning, or a test that reproduces an issue — and we can discuss it further from there. 10 | 11 | Hope you’ll enjoy using DSKit! 12 | -------------------------------------------------------------------------------- /Content/Images/ListGridGallery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Content/Images/ListGridGallery.png -------------------------------------------------------------------------------- /Content/Images/LiveCoding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Content/Images/LiveCoding.png -------------------------------------------------------------------------------- /Content/Images/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Content/Images/Logo.png -------------------------------------------------------------------------------- /Content/Images/Project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Content/Images/Project.png -------------------------------------------------------------------------------- /Content/Images/XCodeTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Content/Images/XCodeTemplate.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DSKitExplorer 4 | // 5 | // Created by Ivan Borinschi on 08.02.2022. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | @main 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | DSAppearance.shared.main = DSKitAppearance() 16 | DSAppearance.shared.userInterfaceStyle = .unspecified 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 22 | // Called when a new scene session is being created. 23 | // Use this method to select a configuration to create the new scene with. 24 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 25 | } 26 | 27 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 28 | // Called when the user discards a scene session. 29 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 30 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Add Frameworks.imageset/Add Frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Add Frameworks.imageset/Add Frameworks.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Add Frameworks.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Add Frameworks.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AllApps-demo.imageset/AllApps-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AllApps-demo.imageset/AllApps-demo.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AllApps-demo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AllApps-demo.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon-Spotlight-40.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "Icon-60.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "Icon-Small@2x.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "Icon-Small@3x.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "Icon-Spotlight-40@2x.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "Icon-Spotlight-40@3x.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "Icon-60@2x.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "Icon-60@3x.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "Icon.png", 53 | "idiom" : "ios-marketing", 54 | "scale" : "1x", 55 | "size" : "1024x1024" 56 | } 57 | ], 58 | "info" : { 59 | "author" : "xcode", 60 | "version" : 1 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Copy items if need.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Copy items if need.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Copy items if need.imageset/Copy items if need.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Copy items if need.imageset/Copy items if need.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverAppearance.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CoverAppearance.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverAppearance.imageset/CoverAppearance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverAppearance.imageset/CoverAppearance.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverCodeExampleHome.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CoverCodeExample.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverCodeExampleHome.imageset/CoverCodeExample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverCodeExampleHome.imageset/CoverCodeExample.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverGetStarted.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CoverGetStarted.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverGetStarted.imageset/CoverGetStarted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverGetStarted.imageset/CoverGetStarted.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverLayout.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CoverLayout.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverLayout.imageset/CoverLayout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/CoverLayout.imageset/CoverLayout.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Embed frameworks.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Embed frameworks.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Embed frameworks.imageset/Embed frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Embed frameworks.imageset/Embed frameworks.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Home.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Home.imageset/Home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Home.imageset/Home.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Icon.imageset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Icon.imageset/Icon.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/LayoutExample.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LayoutExample.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/LayoutExample.imageset/LayoutExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/LayoutExample.imageset/LayoutExample.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/LightDarkModes.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LightDarkModes.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/LightDarkModes.imageset/LightDarkModes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/LightDarkModes.imageset/LightDarkModes.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Welcome.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "DSKit_home.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/Welcome.imageset/DSKit_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/Welcome.imageset/DSKit_home.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/barbershop.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "barbershop.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/barbershop.imageset/barbershop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/barbershop.imageset/barbershop.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/beautysaloon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Screen Shot 2021-03-09 at 10.jpg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "beautysaloon.png", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/beautysaloon.imageset/Screen Shot 2021-03-09 at 10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/beautysaloon.imageset/Screen Shot 2021-03-09 at 10.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/beautysaloon.imageset/beautysaloon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/beautysaloon.imageset/beautysaloon.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/dskitIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "dskitIcon.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/dskitIcon.imageset/dskitIcon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/dskitIcon.imageset/dskitIcon.pdf -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/ecommerce.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ecommerce.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/ecommerce.imageset/ecommerce.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/ecommerce.imageset/ecommerce.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/facebook.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "facebook.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/facebook.imageset/facebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/facebook.imageset/facebook.pdf -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/flowerstore.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "flowerstore_light.jpg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "flowerstore-1.jpg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/flowerstore.imageset/flowerstore-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/flowerstore.imageset/flowerstore-1.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/flowerstore.imageset/flowerstore_light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/flowerstore.imageset/flowerstore_light.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/foodDelivery.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "pexels-photo-1600711.jpeg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/foodDelivery.imageset/pexels-photo-1600711.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/foodDelivery.imageset/pexels-photo-1600711.jpeg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/glasses.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "glasses.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/glasses.imageset/glasses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/glasses.imageset/glasses.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/grocerystore.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "grocerystore.jpg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "grocerystore_dark.jpg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/grocerystore.imageset/grocerystore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/grocerystore.imageset/grocerystore.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/grocerystore.imageset/grocerystore_dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/grocerystore.imageset/grocerystore_dark.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/instagram.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "instagram.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/instagram.imageset/instagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/instagram.imageset/instagram.pdf -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-1.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-1.imageset/picture-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-1.imageset/picture-1.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-10.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-10.imageset/picture-10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-10.imageset/picture-10.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-11.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-11.imageset/picture-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-11.imageset/picture-11.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-12.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-12.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-12.imageset/picture-12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-12.imageset/picture-12.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-13.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-13.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-13.imageset/picture-13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-13.imageset/picture-13.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-2.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-2.imageset/picture-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-2.imageset/picture-2.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-3.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-3.imageset/picture-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-3.imageset/picture-3.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-4.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-4.imageset/picture-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-4.imageset/picture-4.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-5.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-5.imageset/picture-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-5.imageset/picture-5.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-6.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-6.imageset/picture-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-6.imageset/picture-6.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-7.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-7.imageset/picture-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-7.imageset/picture-7.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-8.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-8.imageset/picture-8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-8.imageset/picture-8.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "picture-9.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-9.imageset/picture-9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/picture-9.imageset/picture-9.jpg -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/twitter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "twitter.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/twitter.imageset/twitter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/twitter.imageset/twitter.pdf -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/visa-card-bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "visa-card-bg.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Assets.xcassets/visa-card-bg.imageset/visa-card-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/DSKitExplorer/DSKitExplorer/Assets.xcassets/visa-card-bg.imageset/visa-card-bg.png -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/CustomViewModels/Code/DSCodeUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCodeUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.02.2021. 6 | // 7 | // 8 | 9 | import UIKit 10 | import DSKit 11 | import Splash 12 | 13 | final class DSCodeUIView: UIView, DSReusableUIView { 14 | 15 | @IBOutlet weak var label: UILabel! 16 | var appearance = DSAppearance.shared.main 17 | 18 | public var view: UIView { self } 19 | 20 | public func setUpWith(viewModel: DSViewModel) { 21 | guard let viewModel = viewModel as? DSCodeVM else { return } 22 | update(viewModel: viewModel) 23 | } 24 | 25 | func update(viewModel: DSCodeVM) { 26 | let isLightColor = DSAppearance.shared.main.secondaryView.background.isLight() 27 | let theme: Theme = (isLightColor ?? false) ? .sunset(withFont: Font(size: 10)) : .midnight(withFont: Font(size: 10)) 28 | let output = AttributedStringOutputFormat(theme: theme) 29 | 30 | let highlighter = SyntaxHighlighter(format: output) 31 | let attributedText = highlighter.highlight(viewModel.code) 32 | 33 | label.attributedText = attributedText 34 | label.textAlignment = .left 35 | label.numberOfLines = 0 36 | } 37 | 38 | override func awakeFromNib() { 39 | super.awakeFromNib() 40 | backgroundColor = .clear 41 | } 42 | 43 | class func instanceFromNib() -> DSCodeUIView { 44 | let view: DSCodeUIView = initFromNib() 45 | return view 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Layout/Grid/GridSimpleLayoutVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GridSimpleLayoutVC.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class GridSimpleLayoutVC: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = documentSubtitle 17 | showDemo() 18 | showCode(code: documentCode) 19 | } 20 | 21 | func showDemo() { 22 | 23 | // Demo begin 24 | let viewModels = [1,2,3,4,5].map { (index) -> DSViewModel in 25 | var viewModel = DSImageVM(image: UIImage(named: "picture-\(index)")) 26 | viewModel.height = .absolute(150) 27 | return viewModel 28 | } 29 | 30 | show(content: viewModels.grid()) 31 | // Demo end 32 | } 33 | } 34 | 35 | extension GridSimpleLayoutVC: Documentable { 36 | 37 | var documentViewController: UIViewController? { 38 | return self.viewController 39 | } 40 | 41 | 42 | var documentTitle: String { 43 | "Gird" 44 | } 45 | 46 | var documentSubtitle: String { 47 | "Simple layout" 48 | } 49 | 50 | var documentCode: String { 51 | """ 52 | let viewModels = [1,2,3,4,5].map { (index) -> DSViewModel in 53 | DSBoxVM(text: index.string()) 54 | } 55 | 56 | show(content: viewModels.grid()) 57 | """ 58 | } 59 | 60 | var documentMarkdownFileName: String? { 61 | return nil 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Layout/Lists/ListGroupedLayoutVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListGroupedLayoutVC.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ListGroupedLayoutVC: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = documentTitle 17 | showDemo() 18 | showCode(code: documentCode) 19 | } 20 | 21 | func showDemo() { 22 | 23 | // Demo begin 24 | 25 | let texts = ["Aurora","Inure","Mellifluous","Euphoria","Serendipity"] 26 | 27 | let viewModels: [DSViewModel] = texts.map { (text) -> DSLabelVM in 28 | DSLabelVM(.body, text: text) 29 | } 30 | 31 | show(content: viewModels.list(grouped: true)) 32 | // Demo end 33 | } 34 | } 35 | 36 | extension ListGroupedLayoutVC: Documentable { 37 | 38 | var documentViewController: UIViewController? { 39 | return self.viewController 40 | } 41 | 42 | 43 | var documentTitle: String { 44 | "List" 45 | } 46 | 47 | var documentSubtitle: String { 48 | "Grouped List" 49 | } 50 | 51 | var documentCode: String { 52 | """ 53 | let texts = ["Aurora","Inure","Mellifluous","Euphoria","Serendipity"] 54 | 55 | let viewModels: [DSViewModel] = texts.map { (text) -> DSTextVM in 56 | DSTextVM(.body, text: text) 57 | } 58 | 59 | show(content: viewModels.list()) 60 | """ 61 | } 62 | 63 | var documentMarkdownFileName: String? { 64 | return nil 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Layout/Lists/ListSeparatorLayoutVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListSeparatorLayoutVC.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ListSeparatorLayoutVC: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = "List" 17 | showDemo() 18 | showCode(code: documentCode) 19 | } 20 | 21 | func showDemo() { 22 | 23 | // Demo begin 24 | 25 | let texts = ["Miraculous","Lassitude","Gossamer","Bungalow","Scintilla"] 26 | 27 | let viewModels: [DSViewModel] = texts.map { (text) -> DSLabelVM in 28 | DSLabelVM(.body, text: text) 29 | } 30 | 31 | show(content: viewModels.list(separator: true)) 32 | // Demo end 33 | } 34 | } 35 | 36 | extension ListSeparatorLayoutVC: Documentable { 37 | 38 | var documentViewController: UIViewController? { 39 | return self.viewController 40 | } 41 | 42 | 43 | var documentTitle: String { 44 | "Content" 45 | } 46 | 47 | var documentSubtitle: String { 48 | "Show list with separator" 49 | } 50 | 51 | var documentCode: String { 52 | """ 53 | let texts = ["Miraculous","Lassitude","Gossamer","Bungalow","Scintilla"] 54 | 55 | let viewModels: [DSViewModel] = texts.map { (text) -> DSTextVM in 56 | DSTextVM(.body, text: text) 57 | } 58 | 59 | show(content: viewModels.list()) 60 | """ 61 | } 62 | 63 | var documentMarkdownFileName: String? { 64 | return nil 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Layout/Lists/ListSimpleLayoutVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListSimpleLayoutVC.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ListSimpleLayoutVC: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = documentTitle 17 | showDemo() 18 | showCode(code: documentCode) 19 | } 20 | 21 | func showDemo() { 22 | 23 | // Demo begin 24 | 25 | let texts = ["Petrichor","Sumptuous","Angst","Aesthete","Nadir"] 26 | 27 | let viewModels = texts.map { (text) -> DSViewModel in 28 | DSLabelVM(.body, text: text) 29 | } 30 | 31 | show(content: viewModels.list()) 32 | // Demo end 33 | } 34 | } 35 | 36 | extension ListSimpleLayoutVC: Documentable { 37 | 38 | var documentViewController: UIViewController? { 39 | return self.viewController 40 | } 41 | 42 | 43 | var documentTitle: String { 44 | "List" 45 | } 46 | 47 | var documentSubtitle: String { 48 | "Simple list" 49 | } 50 | 51 | var documentCode: String { 52 | """ 53 | let texts = ["Petrichor","Sumptuous","Angst","Aesthete","Nadir"] 54 | 55 | let viewModels = texts.map { (text) -> DSViewModel in 56 | DSLabel(.body, text: text) 57 | } 58 | 59 | show(content: viewModels.list()) 60 | """ 61 | } 62 | 63 | var documentMarkdownFileName: String? { 64 | return nil 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Show/ShowBottomContentVC.md: -------------------------------------------------------------------------------- 1 | As for the center content of the screen you can easily show content on the bottom of the screen, all you have to do is just call 2 | 3 | ```swift 4 | showBottom(content: [YOUR_SECTION]) 5 | ``` 6 | 7 | everything related to the show content from the show content section is also valid here 8 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Show/ShowContentVC.md: -------------------------------------------------------------------------------- 1 | Displaying content in DSKit is easy, all you have to do is just call one function with content you want to display or want to update. 2 | 3 | ```swift 4 | show(content: [YOUR_SECTION]) 5 | ``` 6 | 7 | Content is composed of two data structures **DSSection** and **DSViewModel** 8 | 9 | **DSSection** - is used to describe how content will be displayed on the screen, in one word: [Layout ](https://dskit.app/layout.html) **DSViewModel** - is used to describe your content on the screen, labels, texts, images, actions, and so on. 10 | 11 | You can display your view models in **Lists, Grids, and Galleries**. 12 | 13 | To easily transform an array of **DSViewModel's** in a section just call **.list() .grid() .gallery()** method on your view models array. 14 | 15 | Every time your need to update content on the screen, add, delete, change position, just change your content structure and `call show(content: [YOUR_SECTION])` DSKit will automatically update the changes, remove non-existent content, or switch position, and it will be animated. 16 | 17 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Show/ShowContentVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShowContentVC.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 05.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import DSKit 11 | 12 | class ShowContentVC: DSViewController { 13 | 14 | override func viewDidLoad() { 15 | 16 | super.viewDidLoad() 17 | title = documentTitle 18 | showDemo() 19 | showCode(code: documentCode) 20 | } 21 | 22 | func showDemo() { 23 | 24 | // Demo begin 25 | 26 | let texts = ["Petrichor","Sumptuous","Angst","Aesthete","Nadir"] 27 | 28 | let viewModels = texts.map { (text) -> DSViewModel in 29 | DSLabelVM(.body, text: text) 30 | } 31 | 32 | show(content: viewModels.list()) 33 | // Demo end 34 | } 35 | } 36 | 37 | extension ShowContentVC: Documentable { 38 | 39 | var documentViewController: UIViewController? { 40 | return self.viewController 41 | } 42 | 43 | var documentTitle: String { 44 | "Content" 45 | } 46 | 47 | var documentSubtitle: String { 48 | "Show Content" 49 | } 50 | 51 | var documentCode: String { 52 | """ 53 | let texts = ["Petrichor","Sumptuous","Angst","Aesthete","Nadir"] 54 | 55 | let viewModels = texts.map { (text) -> DSViewModel in 56 | DSTextVM(.body, text: text) 57 | } 58 | 59 | show(content: viewModels.list()) 60 | """ 61 | } 62 | 63 | var documentMarkdownFileName: String? { 64 | return nil 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Show/ShowTopBottomContentVC.md: -------------------------------------------------------------------------------- 1 | Here is an example of how to show and update content in all positions of the screen 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Show/ShowTopContentVC.md: -------------------------------------------------------------------------------- 1 | As for the center content of the screen you can easily show content on the top of the screen, all you have to do is just call 2 | 3 | ```swift 4 | showTop(content: [YOUR_SECTION]) 5 | ``` 6 | 7 | everything related to the show content from the show content section is also valid here 8 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/SourceCodeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SourceCodeViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | import Splash 11 | 12 | class SourceCodeViewController: DSViewController { 13 | 14 | let code: String 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | title = "Source Code" 19 | show(content: DSActionVM.code(codeString: code, traitCollection.userInterfaceStyle)) 20 | } 21 | 22 | override func viewDidAppear(_ animated: Bool) { 23 | super.viewDidAppear(animated) 24 | } 25 | 26 | init(code: String) { 27 | self.code = code 28 | super.init(nibName: nil, bundle: nil) 29 | } 30 | 31 | required init?(coder aDecoder: NSCoder) { 32 | fatalError("init(coder:) has not been implemented") 33 | // Demo end 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Style/StyleVC.md: -------------------------------------------------------------------------------- 1 | Main DSKit idea is to configure the app appearance once and to not care anymore about spaces colors and typography, if you need just that please read the article about [appearance in DSKit](appearance.html) 2 | 3 | But DSKit offers more than that, you can add small adjustments to specific view models in your UI if you need that. 4 | 5 | Using **style** property on your view model you can adjust `borderStyle` , `colorStyle`, `cornerStyle`,`shadowStyle` 6 | 7 | Explore the example bellow: 8 | 9 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Style/StyleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StyleViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 05.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import DSKit 11 | 12 | class StyleViewController: DSViewController { 13 | 14 | override func viewDidLoad() { 15 | 16 | super.viewDidLoad() 17 | title = "Content Style" 18 | 19 | var style = action(title: "Style", description: "View models style", icon: "rectangle.fill.on.rectangle.fill") 20 | style.didTap { [unowned self] (_ :DSActionVM) in 21 | self.push(StyleVC()) 22 | } 23 | 24 | show(content: style) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Typography/TypographyHtmlVC.md: -------------------------------------------------------------------------------- 1 | # Welcome to DSAppKit 2 | 3 | In order to get started to display DSKit view models on the screen, you should 4 | 5 | ``` 6 | import DSKit 7 | ``` 8 | 9 | and subclass your view controller from **DSViewController**, and you are ready to show content. 10 | 11 | > In order to get started to display DSKit view models on the screen, you should import DSKit and subclass your view controller from **DSViewController**, and you are ready to show content. 12 | 13 | ## Welcome to DSAppKit 14 | 15 | ### Welcome to DSAppKit 16 | 17 | another example of our code here 18 | 19 | ``` 20 | show(content: [viewModels3.gallery(), viewModels5.gallery()]) 21 | ``` 22 | 23 | DSKit and subclass your view controller from **DSViewController** 24 | 25 | ```swift 26 | let numbers = [1,2,3,4,5] 27 | 28 | let viewModels3 = numbers.map { (index) -> DSViewModel in 29 | 30 | var viewModel = DSBoxVM(text: index.string()) 31 | viewModel.height = .absolute(150) 32 | viewModel.width = .fractional(0.7) 33 | return viewModel 34 | } 35 | 36 | let viewModels5 = numbers.map { (index) -> DSViewModel in 37 | 38 | var viewModel = DSBoxVM(text: index.string()) 39 | viewModel.height = .absolute(50) 40 | viewModel.width = .fractional(0.5) 41 | return viewModel 42 | } 43 | 44 | show(content: [viewModels3.gallery(), viewModels5.gallery()]) 45 | 46 | ``` 47 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/Typography/TypographyTextTypesVC.md: -------------------------------------------------------------------------------- 1 | In essence, **typography** is the art of arranging letters and text in a way that makes the copy legible, clear, and visually appealing to the reader. **Typography** involves font style, appearance, and structure, which aims to elicit certain emotions and convey specific messages. -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/Buttons/ButtonViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ButtonViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = "Buttons" 17 | 18 | // Layout 19 | var list = action(title: "List", description: "Button", icon: "list.bullet") 20 | list.didTap { [unowned self] (_ :DSActionVM) in 21 | self.push(ButtonListVC()) 22 | } 23 | 24 | var grid = action(title: "Grid", description: "Button", icon: "rectangle.grid.2x2.fill") 25 | grid.didTap { [unowned self] (_ :DSActionVM) in 26 | self.push(ButtonGridVC()) 27 | } 28 | 29 | var gallery = action(title: "Gallery", description: "Button", icon: "square.lefthalf.fill") 30 | gallery.didTap { [unowned self] (_ :DSActionVM) in 31 | self.push(ButtonGalleryVC()) 32 | } 33 | 34 | // Buttons 35 | var buttons = action(title: "Buttons", description: "Button", icon: "link.circle.fill") 36 | buttons.didTap { [unowned self] (_ :DSActionVM) in 37 | self.push(ButtonsVC()) 38 | } 39 | 40 | let layoutSection = [list, grid, gallery].list().subheadlineHeader("Layout") 41 | let buttonsSection = [buttons].list().subheadlineHeader("Buttons") 42 | 43 | let sections: [DSSection] = [layoutSection, 44 | buttonsSection] 45 | show(content: sections) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/Images/ImageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ImageViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | title = "Image" 16 | 17 | // Layout 18 | var list = action(title: "List", description: "Image", icon: "list.bullet") 19 | list.didTap { [unowned self] (_ :DSActionVM) in 20 | self.push(ImageListVC()) 21 | } 22 | 23 | var grid = action(title: "Grid", description: "Image", icon: "rectangle.grid.2x2.fill") 24 | grid.didTap { [unowned self] (_ :DSActionVM) in 25 | self.push(ImageGridVC()) 26 | } 27 | 28 | var gallery = action(title: "Gallery", description: "Image", icon: "square.lefthalf.fill") 29 | gallery.didTap { [unowned self] (_ :DSActionVM) in 30 | self.push(ImageGalleryVC()) 31 | } 32 | 33 | // Images 34 | var Images = action(title: "Images", description: "Image", icon: "link.circle.fill") 35 | Images.didTap { [unowned self] (_ :DSActionVM) in 36 | self.push(ImagesVC()) 37 | } 38 | 39 | let layoutSection = [list, grid, gallery].list().subheadlineHeader("Layout") 40 | let ImagesSection = [Images].list().subheadlineHeader("Images") 41 | 42 | let sections: [DSSection] = [layoutSection, 43 | ImagesSection] 44 | show(content: sections) 45 | // Demo end 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/Page/PageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SegmentViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class PageViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = "Pages" 17 | 18 | var simplePage = action(title: "Default page", description: "Example of default page", icon: "list.bullet") 19 | simplePage.didTap { [unowned self] (_ :DSActionVM) in 20 | self.push(PageSimplePageVC()) 21 | } 22 | 23 | var insetsPage = action(title: "With insets", description: "Example with insets", icon: "list.bullet") 24 | insetsPage.didTap { [unowned self] (_ :DSActionVM) in 25 | self.push(PageSimplePageWithInsetsVC()) 26 | } 27 | 28 | show(content: [simplePage, insetsPage].list()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/QuantityPicker/QuantityPickerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuantityPickerViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class QuantityPickerViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = "Quantity Picker" 17 | 18 | var quantityPicker = action(title: "Quantity Picker", description: "Simple", icon: "list.bullet") 19 | quantityPicker.didTap { [unowned self] (_ :DSActionVM) in 20 | self.push(QuantityPickerVC()) 21 | } 22 | 23 | show(content: [quantityPicker].list()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldBuiltInValidationVC.md: -------------------------------------------------------------------------------- 1 | **DSKit** contains built-in validation, you can easily add any validation you need for your form using these three properties: 2 | 3 | 1. validateMinimumLength 4 | 2. validateMaximumLength 5 | 3. validationPattern 6 | 7 | Regular expressions snippet: 8 | 9 | ```swift 10 | let patternNumbers = "^[0-9]*$" 11 | let patternLetters = "^[a-zA-Z]*$" 12 | let patternNameUmlaute = "^[\\ü\\ö\\ä\\Ä\\Ü\\Ö\\ß\\u0600-\\u06FFa-zA-Z\\s\\'\\-]*$" 13 | let patternName = "^[\\u0600-\\u06FFa-zA-Z\\s\\'\\-]*$" 14 | let patternLettersAndSpaces = "^[\\u0600-\\u06FFa-zA-Z\\s]*$" 15 | let patternLettersAndNumbers = "^[a-zA-Z0-9]*$" 16 | let patternLettersNumbersAndSpaces = "^[\\u0600-\\u06FFa-zA-Z0-9\\s]*$" 17 | let patternAddressUmlaute = "^[\\ü\\ö\\ä\\Ä\\Ü\\Ö\\ß\\u0600-\\u06FFa-zA-Z0-9\\s\\'\\-]*$" 18 | let patternAddress = "^[\\u0600-\\u06FFa-zA-Z0-9\\s\\'\\-]*$" 19 | let patternEmail = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" 20 | let patternPhoneNumber = "^\\s*(?:\\+?(\\d{1,3}))?([-. (]*(\\d{3})[-. )]*)?((\\d{3})[-. ]*(\\d{2,4})(?:[-.x ]*(\\d+))?)\\s*$" 21 | let patternPhoneNumber2 = "(\\+?( |-|\\.)?\\d{1,3}( |-|\\.)?)?(\\(?\\d{1,5}\\)?|\\d{1,5})( |-|\\.)?(\\d{1,4}( |-|\\.)?\\d{3,4})" 22 | let patternMin8Max20CharsAtLeastOneDigitAtLeastOneLetter = "^(?=.*\\d)((?=.*[a-z])|(?=.*[A-Z])).*$" 23 | let patternCityNameUmlaute = "^[\\ü\\ö\\ä\\Ä\\Ü\\Ö\\ß\\u0600-\\u06FFa-zA-Z\\s\\'\\-]*$" 24 | let patternCityName = "^[\\u0600-\\u06FFa-zA-Z\\s\\'\\-]*$" 25 | ``` 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldCustomInvalidPlaceHolderMessageVC.md: -------------------------------------------------------------------------------- 1 | Customize your error message displayed directly in the text field if the user types an invalid value, you can add a message or an example of what kind of value he should type. 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldCustomValidationVC.md: -------------------------------------------------------------------------------- 1 | If built-in text field validation is not enough for your project requirements you can easily add custom validation to any text field in your form. 2 | Using **handleValidation** closure you are in control, if you implement **handleValidation** closure, all built-in validations will not affect the validation, you are in control for minimum or the maximum number of characters and other validation patterns. 3 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldIconsVC.md: -------------------------------------------------------------------------------- 1 | Customize your text fields with specific icons using apple SF Symbols library 2 | https://developer.apple.com/sf-symbols/ 3 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldInvalidDataVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields with initial invalid values 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldShortcutsVC.md: -------------------------------------------------------------------------------- 1 | **DSKit** contains built-in text field configurations, just pick the one you need and add it to your form, each configuration comes with a specific regular expression validation, icon, minimum and maximum number of required characters for validation. 2 | 3 | We can use a shortcut text field and add some custom elements after initialization, for example changing the minimum of characters for a text field to be valid. 4 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldValidDataVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields with initial valid values 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldsGridVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields in a grid layout 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldsGroupedGridVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields in a grouped grid layout 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldsGroupedVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields grouped in section 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextFields/TextFieldsVC.md: -------------------------------------------------------------------------------- 1 | Display a list of text fields 2 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/ViewModels/TextView/TextViewViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextViewViewController.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class TextViewViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | 15 | super.viewDidLoad() 16 | title = "TextView" 17 | 18 | var textView = action(title: "TextView", description: "Example of default page", icon: "list.bullet") 19 | textView.didTap { [unowned self] (_ :DSActionVM) in 20 | self.push(TextViewSimpleVC()) 21 | } 22 | 23 | show(content: [textView].list()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/WebsiteGenerator/Documentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Document.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 05.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | protocol Documentable { 13 | 14 | var documentTitle: String {get} 15 | var documentSubtitle: String {get} 16 | var documentCode: String {get} 17 | var documentMarkdownFileName: String? {get} 18 | var documentViewController: UIViewController? {get} 19 | } 20 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Documentation/WebsiteGenerator/DocumentsGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebDocumentsGroup.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 06.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct DocumentsGroup { 12 | var title: String 13 | var documents: [Documentable] 14 | } 15 | 16 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Extensions/DSActionVM+SourceCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSActionVM+SourceCode.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import Foundation 9 | import DSKit 10 | import Splash 11 | import UIKit 12 | 13 | extension DSActionVM { 14 | 15 | static func code(codeString: String, _ style: UIUserInterfaceStyle) -> DSActionVM { 16 | 17 | let isLightColor = DSAppearance.shared.main.secondaryView.background.isLight() 18 | 19 | let theme: Theme = !(isLightColor ?? false) ? .sunset(withFont: Font(size: 12)) : .midnight(withFont: Font(size: 12)) 20 | let output = AttributedStringOutputFormat(theme: theme) 21 | let highlighter = SyntaxHighlighter(format: output) 22 | let code = highlighter.highlight(codeString) 23 | let codeText = DSTextComposer() 24 | codeText.add(text: code) 25 | 26 | var action = DSActionVM(composer: codeText) 27 | 28 | action.rightButton(sfSymbolName: "doc.on.doc.fill", style: .small) { 29 | print("Copy Text") 30 | } 31 | 32 | return action 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Extensions/DSTextVM+Description.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSTextVM+Description.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import Foundation 9 | import DSKit 10 | 11 | extension DSLabelVM { 12 | 13 | static func description(text: String) -> DSLabelVM { 14 | return DSLabelVM(.subheadline, text: text) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Extensions/DSViewController+SourceCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewController+SourceCode.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // 7 | 8 | import Foundation 9 | import DSKit 10 | import UIKit 11 | 12 | public extension DSViewController { 13 | 14 | func showSourceCodeButton(code: String) { 15 | 16 | var button = DSButtonVM(title: "Source Code") 17 | button.didTap { [unowned self] (_: DSButtonVM) in 18 | self.push(SourceCodeViewController(code: code)) 19 | } 20 | 21 | showBottom(content: button) 22 | } 23 | 24 | func showCode(code: String) { 25 | 26 | if !ProcessInfo.processInfo.arguments.contains("UI_TEST_MODE") && (ProcessInfo.processInfo.environment["DOCUMENT"] == nil) { 27 | 28 | var codeViewModel = DSCodeVM(code: code) 29 | 30 | codeViewModel.didTap { (_: DSCodeVM) in 31 | let activityViewController = UIActivityViewController(activityItems: [code], applicationActivities: nil) 32 | UIApplication.shared.windows.first?.rootViewController?.present(activityViewController, animated: true, completion: nil) 33 | } 34 | 35 | let text = DSLabelVM(.caption2, text: "Tap on code to open share sheet, to send example code directly to your mac, or copy it.") 36 | showBottom(content: [text.list(), codeViewModel.gallery()]) 37 | 38 | } else { 39 | 40 | showPoweredBy() 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /DSKitExplorer/DSKitExplorer/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // DSKitExplorer 4 | // 5 | // Created by Ivan Borinschi on 08.02.2022. 6 | // 7 | 8 | import UIKit 9 | import DSKit 10 | 11 | class ViewController: DSViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | title = "Components" 16 | let groups = DocumentsGroups() 17 | self.show(content: groups.sections(presenter: self)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 DSKit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "ActiveLabel", 6 | "repositoryURL": "https://github.com/imodeveloperlab/ActiveLabel.swift", 7 | "state": { 8 | "branch": null, 9 | "revision": "ad145ba677be2f8e342033a1cadd8fee4059e017", 10 | "version": "1.1.7" 11 | } 12 | }, 13 | { 14 | "package": "Cartography", 15 | "repositoryURL": "https://github.com/robb/Cartography", 16 | "state": { 17 | "branch": null, 18 | "revision": "b75197ea134f42b5feafb04b526b37eb1a41034b", 19 | "version": "4.0.0" 20 | } 21 | }, 22 | { 23 | "package": "Fakery", 24 | "repositoryURL": "https://github.com/vadymmarkov/Fakery", 25 | "state": { 26 | "branch": null, 27 | "revision": "71cb3bf36a808534659d1248780c2bf3c4c4fc91", 28 | "version": "5.1.0" 29 | } 30 | }, 31 | { 32 | "package": "HorizonCalendar", 33 | "repositoryURL": "https://github.com/airbnb/HorizonCalendar.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "1e98736e42fe4e5bea39ce8b89838641f2261c32", 37 | "version": "1.13.3" 38 | } 39 | }, 40 | { 41 | "package": "Kingfisher", 42 | "repositoryURL": "https://github.com/onevcat/Kingfisher", 43 | "state": { 44 | "branch": null, 45 | "revision": "5b92f029fab2cce44386d28588098b5be0824ef5", 46 | "version": "7.11.0" 47 | } 48 | } 49 | ] 50 | }, 51 | "version": 1 52 | } 53 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Colors/DSColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 16.12.2020. 6 | // 7 | 8 | import UIKit 9 | 10 | public class DSColor { 11 | 12 | /// Generate light and dark color for dynamic interfaces 13 | /// - Parameters: 14 | /// - light: UIColor for light interface 15 | /// - dark: UIColor for dark interface 16 | /// - Returns: UIColor 17 | public static func color(light: UIColor, dark: UIColor) -> UIColor { 18 | return UIColor { (traitCollection: UITraitCollection) -> UIColor in 19 | if traitCollection.userInterfaceStyle == .dark { 20 | return dark 21 | } else { 22 | return light 23 | } 24 | } 25 | } 26 | 27 | /// Generate light and dark color for dynamic interfaces 28 | /// - Parameters: 29 | /// - light: UIColor fo light interface 30 | /// - dark: UIColor for dark interface 31 | /// - Returns: UIColor 32 | public static func color(light: Int, dark: Int) -> UIColor { 33 | return color(light: UIColor(light), dark: UIColor(dark)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignableButtonColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSDesignableButtonColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Button colors 12 | public struct DSDesignableButtonColor: Equatable, Hashable { 13 | 14 | /// Init designable button colors 15 | /// - Parameters: 16 | /// - background: UIColor 17 | /// - title: UIColor 18 | public init(background: UIColor, title: UIColor) { 19 | self.background = background 20 | self.title = title 21 | } 22 | 23 | /// Button background color 24 | public var background: UIColor 25 | 26 | /// Button title color 27 | public var title: UIColor 28 | } 29 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignableNavigationBarColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSDesignableNavigationBarColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Navigation bar colors 12 | public struct DSDesignableNavigationBarColor { 13 | 14 | /// Init navigation bar colors 15 | /// - Parameters: 16 | /// - buttons: UIColor 17 | /// - text: UIColor 18 | /// - bar: UIColor 19 | /// - translucent: Bool 20 | public init(buttons: UIColor, text: UIColor, bar: UIColor, translucent: Bool = false) { 21 | self.buttons = buttons 22 | self.text = text 23 | self.bar = bar 24 | self.translucent = translucent 25 | } 26 | 27 | /// Buttons color 28 | public var buttons: UIColor 29 | /// Text color 30 | public var text: UIColor 31 | /// Bar color 32 | public var bar: UIColor 33 | /// Translucent 34 | public var translucent: Bool 35 | } 36 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignablePriceColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurrencyColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Price colors 12 | public struct DSDesignablePriceColor: Equatable, Hashable { 13 | 14 | /// Init price colors 15 | /// - Parameters: 16 | /// - currency: UIColor 17 | /// - amount: UIColor 18 | public init(currency: UIColor, amount: UIColor, regularAmount: UIColor, badgeBackground: UIColor = .red, badgeText: UIColor = .white, badgeCornerRadius: CGFloat = 4.0) { 19 | self.currency = currency 20 | self.amount = amount 21 | self.badgeText = badgeText 22 | self.badgeBackground = badgeBackground 23 | self.badgeCornerRadius = badgeCornerRadius 24 | self.regularAmount = regularAmount 25 | } 26 | 27 | /// Currency color 28 | var currency: UIColor 29 | 30 | /// Amount color 31 | var amount: UIColor 32 | 33 | /// Regular amount color 34 | var regularAmount: UIColor 35 | 36 | /// Badge background color 37 | var badgeBackground: UIColor 38 | 39 | /// Badge text color 40 | var badgeText: UIColor 41 | 42 | /// Badge corner radius 43 | var badgeCornerRadius: CGFloat 44 | } 45 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignableTabbarColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSDesignableTabbarColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Tabbar colors 12 | public struct DSDesignableTabbarColor { 13 | 14 | /// Init tabbar colors 15 | /// - Parameters: 16 | /// - barTint: UIColor 17 | /// - itemTint: UIColor 18 | /// - unselectedItemTint: UIColor 19 | /// - badge: UIColor 20 | /// - translucent: Bool 21 | public init(barTint: UIColor, 22 | itemTint: UIColor, 23 | unselectedItemTint: UIColor, 24 | badge: UIColor, 25 | translucent: Bool = false) { 26 | 27 | self.barTint = barTint 28 | self.itemTint = itemTint 29 | self.unselectedItemTint = unselectedItemTint 30 | self.badge = badge 31 | self.translucent = translucent 32 | } 33 | 34 | /// Bar tint color 35 | public var barTint: UIColor 36 | 37 | /// Item tint color 38 | public var itemTint: UIColor 39 | 40 | /// Unselected item tint 41 | public var unselectedItemTint: UIColor 42 | 43 | /// Badge color 44 | public var badge: UIColor 45 | 46 | /// Translucent 47 | public var translucent: Bool 48 | } 49 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignableTextFieldColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Text field colors 12 | public struct DSDesignableTextFieldColor: Equatable, Hashable { 13 | 14 | /// Init designable text field color 15 | /// - Parameters: 16 | /// - border: UIColor 17 | /// - background: UIColor 18 | /// - text: UIColor 19 | /// - placeHolder: UIColor 20 | public init(border: UIColor, 21 | background: UIColor, 22 | text: UIColor, 23 | placeHolder: UIColor) { 24 | self.border = border 25 | self.background = background 26 | self.text = text 27 | self.placeHolder = placeHolder 28 | } 29 | 30 | /// Border color 31 | public var border: UIColor 32 | 33 | /// Background color 34 | public var background: UIColor 35 | 36 | /// Text color 37 | public var text: UIColor 38 | 39 | /// Placeholder color 40 | public var placeHolder: UIColor 41 | } 42 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/Designable/DSDesignableViewColors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BackgroundColors.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View colors 12 | public struct DSDesignableViewColors: Equatable, Hashable { 13 | 14 | /// Init designable view colors 15 | /// - Parameters: 16 | /// - button: DSDesignableButtonColor 17 | /// - text: DSDesignableTextColor 18 | /// - background: UIColor 19 | /// - separator: UIColor 20 | /// - cornerRadius: CGFloat 21 | public init(button: DSDesignableButtonColor, 22 | text: DSDesignableTextColor, 23 | textField: DSDesignableTextFieldColor, 24 | background: UIColor, 25 | separator: UIColor, 26 | cornerRadius: CGFloat) { 27 | 28 | self.button = button 29 | self.text = text 30 | self.background = background 31 | self.separator = separator 32 | self.cornerRadius = cornerRadius 33 | self.textField = textField 34 | } 35 | 36 | /// Any button on, view colors 37 | public var button: DSDesignableButtonColor 38 | 39 | /// Any text on, view colors 40 | public var text: DSDesignableTextColor 41 | 42 | /// Any textfield on, view colors 43 | public var textField: DSDesignableTextFieldColor 44 | 45 | /// View background colors 46 | public var background: UIColor 47 | 48 | /// View separator colors 49 | public var separator: UIColor 50 | 51 | /// View corner radius 52 | public var cornerRadius: CGFloat 53 | } 54 | -------------------------------------------------------------------------------- /Sources/DSKit/Appearance/UIColor+String.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+String.swift 3 | // DSKit+AppearanceMaker 4 | // 5 | // Created by Borinschi Ivan on 17.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | var dsDescription: String { 13 | let light = self.resolvedColor(with: UITraitCollection.init(userInterfaceStyle: .light)) 14 | let dark = self.resolvedColor(with: UITraitCollection.init(userInterfaceStyle: .dark)) 15 | return "DSColor.color(light: 0x\(light.hexRGBColor), dark: 0x\(dark.hexRGBColor))" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/DSCollectionViewPosition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionViewPosition.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 23.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum DSCollectionViewPosition { 12 | case top 13 | case center 14 | case bottom 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/Helpers/DSCollectionView+Config.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionView+Config.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DSCollectionView { 12 | 13 | public var isPagingEnabled: Bool { 14 | get { view.isPagingEnabled } 15 | set { view.isPagingEnabled = newValue } 16 | } 17 | 18 | public var showsHorizontalScrollIndicator: Bool { 19 | get { view.showsHorizontalScrollIndicator } 20 | set { view.showsHorizontalScrollIndicator = newValue } 21 | } 22 | 23 | public var showsVerticalScrollIndicator: Bool { 24 | get { view.showsVerticalScrollIndicator } 25 | set { view.showsVerticalScrollIndicator = newValue } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/Helpers/DSCollectionView+Forms.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionView+Forms.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DSCollectionView { 12 | 13 | func isCurrentFormValid(_ validate: @escaping (Bool) -> Void) { 14 | 15 | guard !self.adaptedContent.isEmpty else { 16 | validate(true) 17 | return 18 | } 19 | 20 | var verifiedViewModels: Int = 0 21 | 22 | var isValid = true 23 | 24 | for section in adaptedContent { 25 | 26 | for model in section.viewModels { 27 | 28 | guard let model = model as? DSTextFieldVM else { 29 | continue 30 | } 31 | 32 | // Request view model to validate self 33 | model.validateTextField?() 34 | 35 | model.isValid(text: model.text, validateEmptyTextField: false, { isViewTextFieldValid in 36 | 37 | verifiedViewModels += 1 38 | 39 | if !isViewTextFieldValid { 40 | isValid = false 41 | } 42 | 43 | if verifiedViewModels == self.adaptedContent.totalTextFieldViewModelsCount { 44 | validate(isValid) 45 | } 46 | }) 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/Helpers/DSCollectionView+Identifiers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionView+Sections.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DSCollectionView { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/Helpers/DSCollectionView+Register.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionView+Register.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSCollectionView { 12 | 13 | public func registerCellClassIfNeed(for reusableIdentifier: String, cellClass: AnyClass) { 14 | if !registeredCells.contains(reusableIdentifier) { 15 | self.view.register(cellClass, forCellWithReuseIdentifier: reusableIdentifier) 16 | registeredCells.append(reusableIdentifier) 17 | } 18 | } 19 | 20 | public func registerClassForReusableViewIfNeed(kind: String, reuseIdentifier: String, viewClass: AnyClass) { 21 | if !registeredViews.contains(reuseIdentifier) { 22 | self.view.register(viewClass, forSupplementaryViewOfKind: kind, withReuseIdentifier: reuseIdentifier) 23 | registeredViews.append(reuseIdentifier) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/DSKit/CollectionView/Helpers/DSCollectionView+Reload.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCollectionView+Reload.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DSCollectionView { 12 | 13 | /// Reload content 14 | /// - Parameters: 15 | /// - newContent: New content to show 16 | /// - scrollToBottom: Scroll to bottom after reload, default is `false` 17 | func reload(content newContent: [DSSection], animated: Bool = false, scrollToBottom: Bool = false) { 18 | show(content: newContent, animated: animated, scrollToBottom: scrollToBottom) 19 | } 20 | 21 | /// Reload current content 22 | /// - Parameter scrollToBottom: Scroll to bottom after reload, default is `false` 23 | func reload(scrollToBottom: Bool = false, animated: Bool = false) { 24 | self.reload(content: self.originalContent, animated: animated, scrollToBottom: scrollToBottom) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImage+DSViewable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSImage+DSViewAble.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 22.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSImage: DSViewable { 12 | 13 | public func view(_ designableViewColors: DSDesignableViewColors) -> UIView { 14 | let imageView = UIImageView() 15 | imageView.setImage(self, designableViewColors: designableViewColors) 16 | return imageView 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIButtonExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 22.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct DSImage: Equatable, Hashable { 12 | 13 | public var size: DSImageSize 14 | public var displayStyle: DSImageDisplayStyle 15 | public var content: DSImageContent 16 | public var contentMode: DSImageContentMode 17 | public var tintColor: DSImageTintColor 18 | 19 | public init(content: DSImageContent, 20 | displayStyle: DSImageDisplayStyle = .default, 21 | size: DSImageSize = .size(CGSize(width: 25, height: 25)), 22 | tintColor: DSImageTintColor, 23 | contentMode: DSImageContentMode = .scaleAspectFit) { 24 | 25 | self.content = content 26 | self.displayStyle = displayStyle 27 | self.tintColor = tintColor 28 | self.size = size 29 | self.contentMode = contentMode 30 | } 31 | } 32 | 33 | extension UIImageView { 34 | 35 | func setImage(_ image: DSImage, 36 | designableViewColors: DSDesignableViewColors) { 37 | 38 | setImageContent(image.content) 39 | setImageTintColor(image.tintColor, designableViewColors: designableViewColors) 40 | setImageDisplayStyle(image.displayStyle, size: image.size, cornerRadius: designableViewColors.cornerRadius) 41 | setImageSize(image.size) 42 | setImageContentMode(image.contentMode) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImageContentMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSImageTintColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum DSImageContentMode: Equatable, Hashable { 12 | 13 | case scaleAspectFit // contents scaled to fit with fixed aspect. remainder is transparent 14 | case scaleAspectFill // contents scaled to fill with fixed aspect. some portion of content may be clipped. 15 | 16 | public var rawValue: String { 17 | switch self { 18 | case .scaleAspectFit: 19 | return "ScaleAspectFit" 20 | case .scaleAspectFill: 21 | return "ScaleAspectFill" 22 | } 23 | } 24 | } 25 | 26 | extension UIImageView { 27 | 28 | /// Image Content mode 29 | /// - Parameters: 30 | /// - contentMode: DSImageContentMode 31 | func setImageContentMode(_ contentMode: DSImageContentMode) { 32 | 33 | switch contentMode { 34 | case .scaleAspectFill: 35 | self.contentMode = .scaleAspectFill 36 | case .scaleAspectFit: 37 | self.contentMode = .scaleAspectFit 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImageHeight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSImageHeight.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum DSImageHeight: Equatable, Hashable { 12 | 13 | case equalTo(CGFloat) 14 | case zero 15 | case unknown 16 | 17 | var rawValue: String { 18 | switch self { 19 | case .equalTo(let height): 20 | return "ImageHeight\(height)" 21 | case .zero: 22 | return "ImageHeightZero" 23 | case .unknown: 24 | return "ImageHeightUnknown" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImageSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Cartography 11 | 12 | public enum DSImageSize: Equatable, Hashable { 13 | 14 | case size(CGSize) 15 | case unknown 16 | 17 | public var rawValue: String { 18 | switch self { 19 | case .size(let size): 20 | return "ImageSize_\(size.width)x\(size.height)" 21 | case .unknown: 22 | return "UnknownSize" 23 | } 24 | } 25 | 26 | var width: CGFloat? { 27 | switch self { 28 | case .size(let size): 29 | return size.width 30 | case .unknown: 31 | return nil 32 | } 33 | } 34 | 35 | var height: CGFloat? { 36 | switch self { 37 | case .size(let size): 38 | return size.height 39 | case .unknown: 40 | return nil 41 | } 42 | } 43 | } 44 | 45 | extension UIImageView { 46 | 47 | func setImageSize(_ size: DSImageSize) { 48 | 49 | switch size { 50 | case .size(let size): 51 | 52 | constrain(self) { (imageView) in 53 | imageView.width == size.width 54 | imageView.height == size.height 55 | } 56 | 57 | case .unknown: 58 | 59 | constrain(self) { (imageView) in 60 | imageView.width >= 0 61 | imageView.height >= 0 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Image/DSImageTintColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSImageTintColor.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum DSImageTintColor: Equatable, Hashable { 12 | 13 | case `default` 14 | case text(DSTextColor) 15 | case custom(UIColor) 16 | 17 | public var rawValue: String { 18 | switch self { 19 | case .text(_): 20 | return "DSImageTintColorTextColor" 21 | case .custom(_): 22 | return "DSImageTintColorCustom" 23 | case .default: 24 | return "DSImageTintColorDefault" 25 | } 26 | } 27 | } 28 | 29 | extension UIImageView { 30 | 31 | func setImageTintColor(_ color: DSImageTintColor, designableViewColors: DSDesignableViewColors) { 32 | 33 | switch color { 34 | case .text(let textColor): 35 | tintColor = textColor.getColor(designableTextColor: designableViewColors.text) 36 | case .custom(let uiColor): 37 | tintColor = uiColor 38 | case .default: 39 | tintColor = designableViewColors.text.subheadline 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Price/DSPrice+Viewable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSPrice+Viewable.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 22.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSPrice: DSViewable { 12 | 13 | func view(_ designableViewColors: DSDesignableViewColors) -> UIView { 14 | 15 | let label = UILabel() 16 | let composer = DSTextComposer() 17 | composer.add(price: self) 18 | label.set(text: composer, designableTextColor: designableViewColors.text) 19 | return label 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Text/DSTextComposer+DSViewable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSText.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 14.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSTextComposer: DSViewable { 12 | 13 | func view(_ designableViewColors: DSDesignableViewColors) -> UIView { 14 | let label = UILabel() 15 | label.set(text: self, designableTextColor: designableViewColors.text) 16 | return label 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Text/DSTextComposer+ViewModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSTextComposer+ViewModels.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 05.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension DSTextComposer { 12 | 13 | /// Get text view model from composer 14 | /// - Returns: DSTextVM 15 | func textViewModel() -> DSLabelVM { 16 | return DSLabelVM(composer: self) 17 | } 18 | 19 | /// Get action view model from composer 20 | /// - Returns: DSTextVM 21 | func actionViewModel() -> DSActionVM { 22 | return DSActionVM(composer: self) 23 | } 24 | 25 | /// Checkbox Action ViewModel 26 | /// - Parameter selected: Bool 27 | /// - Returns: DSActionVM 28 | func checkboxActionViewModel(selected: Bool) -> DSActionVM { 29 | 30 | let appearance = DSAppearance.shared.main 31 | let icon = selected ? "checkmark.circle.fill" : "circle" 32 | let color = selected ? appearance.semanticGreenColor : appearance.secondaryView.text.subheadline.withAlphaComponent(0.5) 33 | 34 | var action = DSActionVM(composer: self) 35 | action.rightIcon(sfSymbolName: icon, style: selected ? .custom(size: 15, weight: .medium) : .custom(size: 12, weight: .light), tintColor: .custom(color)) 36 | return action 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Text/DSTextParagraph.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSTextParagraph.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct DSTextParagraph: Equatable, Hashable { 12 | 13 | let type: DSTextParagraphType 14 | let newLine: Bool 15 | let spacing: CGFloat 16 | let lineSpacing: CGFloat 17 | let maximumLineHeight: CGFloat 18 | 19 | static func == (lhs: DSTextParagraph, rhs: DSTextParagraph) -> Bool { 20 | return 21 | lhs.newLine == rhs.newLine && 22 | lhs.spacing == rhs.spacing && 23 | lhs.type == rhs.type 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/Text/DSTextParagraphType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSTextParagraphType.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum DSTextParagraphType: Equatable, Hashable { 12 | case attributed(text: NSAttributedString) 13 | case text(icon: UIImage?, text: String, font: UIFont, color: DSTextColor) 14 | case price(price: DSPrice, size: DSPrice.DisplaySize, color: DSPrice.DisplayColor) 15 | case symbol(sfSymbol: String, style: DSSFSymbolConfigStyle, tint: DSTextColor) 16 | case symbols(sfSymbols: [String], style: DSSFSymbolConfigStyle, tint: DSTextColor) 17 | case image(image: UIImage, size: CGSize) 18 | case badge(text: String, type: DSTextType, backgroundColor: UIColor, cornerRadius: CGFloat) 19 | } 20 | -------------------------------------------------------------------------------- /Sources/DSKit/ContentModels/View/DSViewPosition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewPosition.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum DSViewPosition { 12 | case top 13 | case center 14 | } 15 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/CGFloat+UIEdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGFloat+UIEdgeInsets.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGFloat { 12 | 13 | /// Transform CGFloat to UIEdgeInsets with CGFloat 14 | public var edgeInsets: UIEdgeInsets { 15 | return UIEdgeInsets(top: self, left: self, bottom: self, right: self) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/Double+Rounded.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DoubleExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Double { 12 | 13 | /// Rounds the double to decimal places value 14 | /// - Parameter places: Place to round to, Example: Double(123.456789).rounded(toPlaces: 1) will equal to 123.5 15 | /// - Returns: Double 16 | func rounded(toPlaces places: Int) -> Double { 17 | let divisor = pow(10.0, Double(places)) 18 | return (self * divisor).rounded() / divisor 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/Int+Cents.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IntExtension.swift 3 | // MMModules 4 | // 5 | // Created by Borinschi Ivan on 5/23/17. 6 | // Copyright © 2017 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int { 12 | 13 | func toNSNumber() -> NSNumber { 14 | return NSNumber(value: self) 15 | } 16 | 17 | func stringAmount() -> String { 18 | return toNSNumber().fromCents().stringFormatted(withNumberOfDecimals: 2) 19 | } 20 | 21 | func toCents() -> Int { 22 | return self * 100 23 | } 24 | 25 | func string() -> String { 26 | return "\(self)" 27 | } 28 | 29 | func fromCents() -> Int { 30 | return self / 100 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/Int+Plural.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Int+Plural.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int { 12 | 13 | /// Return correct form of the string, singular or plural. 14 | /// 15 | /// - Parameters: 16 | /// - singular: Singular form of the string 17 | /// - plural: Plural form of the string 18 | /// - Returns: String with correct form. 19 | func getCorrectForm(singular: String, plural: String) -> String { 20 | if self == 1 { 21 | return singular 22 | } else if self > 1 { 23 | return plural 24 | } else { 25 | return plural 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/Int+TimeString.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Int+TimeString.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int { 12 | 13 | /// Convert int to time string, 120 seconds to 01:59 14 | /// 15 | /// - Returns: String 16 | func timeString() -> String { 17 | 18 | let minutes = (self % 3600) / 60 19 | let seconds = (self % 3600) % 60 20 | 21 | var minutesString = "\(minutes)" 22 | var secondsString = "\(seconds)" 23 | 24 | if minutesString.count == 1 { 25 | minutesString = "0\(minutesString)" 26 | } 27 | 28 | if secondsString.count == 1 { 29 | secondsString = "0\(secondsString)" 30 | } 31 | 32 | return "\(minutesString):\(secondsString)" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/NSNumber+Cents.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumberExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 5/23/20. 6 | // Copyright © 2020 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension NSNumber { 12 | 13 | func stringFormatted(withNumberOfDecimals numberOfDecimals: Int) -> String { 14 | 15 | let formatter = NumberFormatter() 16 | formatter.locale = Locale(identifier: "en_US") 17 | formatter.numberStyle = .decimal 18 | formatter.maximumFractionDigits = numberOfDecimals 19 | formatter.minimumFractionDigits = numberOfDecimals 20 | 21 | guard let finalValue = formatter.string(from: self) else { 22 | return "0.00" 23 | } 24 | 25 | return finalValue 26 | } 27 | 28 | func stringFormattedAmount() -> String { 29 | return stringFormatted(withNumberOfDecimals: 2) 30 | } 31 | 32 | func toCents() -> NSNumber { 33 | return NSNumber(value: lround(self.doubleValue * 100)) 34 | } 35 | 36 | func fromCents() -> NSNumber { 37 | return NSNumber(value: self.doubleValue / 100) 38 | } 39 | 40 | class func divideFloat(first: Float, second: Float) -> Float { 41 | 42 | if first == 0 || second == 0 { 43 | return Float(0) 44 | } 45 | 46 | let result = first/second 47 | 48 | if result > 0 { 49 | return Float(result) 50 | } else { 51 | return Float(0) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/Notification+FrameAndDuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.11.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension Notification { 12 | 13 | /// Get keyboard final frame and animation duration 14 | /// - Returns: frame: CGRect, duration: Double) 15 | func frameAndDuration() -> (frame: CGRect, duration: Double)? { 16 | 17 | guard let keyboardFrame = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, 18 | let duration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { 19 | return nil 20 | } 21 | 22 | return (frame: keyboardFrame, duration: duration) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/String+AppName.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+AppName.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension String { 12 | 13 | static func appName() -> String { 14 | return Bundle.main.infoDictionary!["CFBundleDisplayName"] as? String ?? "App" 15 | } 16 | 17 | func style(_ appearance: DSDesignable) -> String { 18 | return self 19 | } 20 | 21 | func toAccessibilityIdentifierStyle() -> String { 22 | return self.replace(target: " ", withString: "_").replace(target: "-", withString: "_").uppercased() 23 | } 24 | 25 | func replace(target: String, withString: String) -> String { 26 | return self.replacingOccurrences(of: target, with: withString, options: NSString.CompareOptions.literal, range: nil) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/String+Currency.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Currency.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | var currencySymbol: String { 13 | switch self { 14 | case "EUR": return "€" 15 | case "USD": return "$" 16 | case "GBP": return "£" 17 | default: return self 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/String+EstimatedHeight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+EstimatedHeight.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 05.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension String { 12 | 13 | /// Get estimated height for text 14 | /// - Parameters: 15 | /// - textType: DSTextType 16 | /// - section: DSSection 17 | /// - layoutEnvironment: NSCollectionLayoutEnvironment 18 | /// - Returns: DSViewModelHeight 19 | func estimatedHeight(textType: DSTextType, section: DSSection, _ layoutEnvironment: NSCollectionLayoutEnvironment?) -> DSViewModelHeight { 20 | 21 | let width = section.sectionWidth(layoutEnvironment) 22 | let height = self.height(forFixedWidth: width, font: textType.style.font.getFont()) 23 | return .estimated(height) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/String+OpenURL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+OpenURL.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension String { 12 | 13 | func open() { 14 | 15 | if let url = URL(string: self) { 16 | 17 | if self.isEmail() { 18 | self.openEmail() 19 | } else { 20 | URLOpener.open(url, options: [:], completion: nil) 21 | } 22 | } 23 | } 24 | 25 | @discardableResult 26 | func openEmail() -> URL? { 27 | let email = self 28 | if let url = URL(string: "mailto:\(email)") { 29 | URLOpener.open(url, options: [:], completion: nil) 30 | return url 31 | } 32 | return nil 33 | } 34 | 35 | @discardableResult 36 | 37 | func openPhone() -> URL? { 38 | var number = self.replacingOccurrences(of: "+", with: "00") 39 | number = number.replacingOccurrences(of: " ", with: "") 40 | guard let phoneNumber = URL(string: "tel://" + number) else { 41 | return nil 42 | } 43 | 44 | URLOpener.open(phoneNumber, options: [:], completion: nil) 45 | return phoneNumber 46 | } 47 | 48 | func isEmail() -> Bool { 49 | return self.contains("@") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/String+Random.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Random.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | 13 | public func randomString(length: Int) -> String { 14 | 15 | let letters: NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 16 | let len = UInt32(letters.length) 17 | 18 | var randomString = "" 19 | 20 | for _ in 0 ..< length { 21 | let rand = arc4random_uniform(len) 22 | var nextChar = letters.character(at: Int(rand)) 23 | randomString += NSString(characters: &nextChar, length: 1) as String 24 | } 25 | 26 | return randomString 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIApplication+KeyWindow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+KeyWindow.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 29.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIApplication { 12 | 13 | func getKeyWindow() -> UIWindow? { 14 | 15 | UIApplication.shared.connectedScenes 16 | .filter({$0.activationState == .foregroundActive}) 17 | .map({$0 as? UIWindowScene}) 18 | .compactMap({$0}) 19 | .first?.windows 20 | .filter({$0.isKeyWindow}).first 21 | } 22 | 23 | var isRTL: Bool { 24 | UIApplication.shared.getKeyWindow()?.effectiveUserInterfaceLayoutDirection == .rightToLeft 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIApplication+TopViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+KeyWindow.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 29.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIViewController { 12 | 13 | /// Do not change this code ! 14 | /// - Returns: UIViewController 15 | func topMostViewController() -> UIViewController? { 16 | 17 | if self.presentedViewController == nil { 18 | 19 | if let navigation = self as? UINavigationController { 20 | return navigation.visibleViewController?.topMostViewController() ?? nil 21 | } 22 | 23 | return self 24 | } 25 | if let navigation = self.presentedViewController as? UINavigationController { 26 | return navigation.visibleViewController?.topMostViewController() ?? nil 27 | } 28 | 29 | if let tab = self.presentedViewController as? UITabBarController { 30 | if let selectedTab = tab.selectedViewController { 31 | return selectedTab.topMostViewController() 32 | } 33 | return tab.topMostViewController() 34 | } 35 | return self.presentedViewController!.topMostViewController() 36 | } 37 | } 38 | 39 | extension UIApplication { 40 | func topMostViewController() -> UIViewController? { 41 | 42 | let controller = UIApplication.shared.getKeyWindow()?.rootViewController?.topMostViewController() 43 | 44 | return controller 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIButton+Colors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+Colors.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIButton { 12 | 13 | func setBackgroundColor(color: UIColor, forState: UIControl.State) { 14 | 15 | UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) 16 | UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor) 17 | UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1)) 18 | let colorImage = UIGraphicsGetImageFromCurrentImageContext() 19 | UIGraphicsEndImageContext() 20 | self.setBackgroundImage(colorImage, for: forState) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIButton+EdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+EdgeInsets.swift 3 | // 4 | // 5 | // Created by Zalan Mergl on 2022. 06. 10.. 6 | // 7 | 8 | import UIKit 9 | 10 | public extension UIButton { 11 | func centerVertically(padding: CGFloat = 3.0) { 12 | if let imageViewSize = self.imageView?.frame.size, 13 | let titleLabelSize = self.titleLabel?.frame.size { 14 | 15 | let imageHeight: CGFloat = 30 16 | let totalHeight = imageHeight + titleLabelSize.height + padding 17 | let topMargin = (totalHeight) / 3 18 | 19 | self.imageEdgeInsets = UIEdgeInsets( 20 | top: -(totalHeight - imageHeight - topMargin), 21 | left: 0.0, 22 | bottom: 0.0, 23 | right: -titleLabelSize.width 24 | ) 25 | 26 | self.titleEdgeInsets = UIEdgeInsets( 27 | top: 0.0, 28 | left: -imageViewSize.width, 29 | bottom: -(totalHeight - titleLabelSize.height + (topMargin / 2)), 30 | right: 0.0 31 | ) 32 | 33 | self.contentEdgeInsets = UIEdgeInsets( 34 | top: 0.0, 35 | left: 0.0, 36 | bottom: titleLabelSize.height, 37 | right: 0.0 38 | ) 39 | } 40 | } 41 | 42 | func moveImageEdgeInset(by delta: CGFloat) { 43 | imageEdgeInsets = UIEdgeInsets(top: 0, left: delta, bottom: 0, right: -delta) 44 | } 45 | 46 | func moveTitleEdgeInset(by delta: CGFloat) { 47 | titleEdgeInsets = UIEdgeInsets(top: 0, left: delta, bottom: 0, right: -delta) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIColor+Equtable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Equatable.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | 13 | static func == (l: UIColor, r: UIColor) -> Bool { 14 | var r1: CGFloat = 0 15 | var g1: CGFloat = 0 16 | var b1: CGFloat = 0 17 | var a1: CGFloat = 0 18 | l.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) 19 | var r2: CGFloat = 0 20 | var g2: CGFloat = 0 21 | var b2: CGFloat = 0 22 | var a2: CGFloat = 0 23 | r.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) 24 | return r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2 25 | } 26 | } 27 | 28 | func == (l: UIColor?, r: UIColor?) -> Bool { 29 | let l = l ?? .clear 30 | let r = r ?? .clear 31 | return l == r 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIColor+IsLight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+IsLight.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 26.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIColor { 12 | 13 | // Check if the color is light or dark, as defined by the injected lightness threshold. 14 | // Some people report that 0.7 is best. I suggest to find out for yourself. 15 | // A nil value is returned if the lightness couldn't be determined. 16 | func isLight(threshold: Float = 0.5) -> Bool? { 17 | let originalCGColor = self.cgColor 18 | 19 | // Now we need to convert it to the RGB colorspace. UIColor.white / UIColor.black are greyscale and not RGB. 20 | // If you don't do this then you will crash when accessing components index 2 below when evaluating greyscale colors. 21 | let RGBCGColor = originalCGColor.converted(to: CGColorSpaceCreateDeviceRGB(), intent: .defaultIntent, options: nil) 22 | guard let components = RGBCGColor?.components else { 23 | return nil 24 | } 25 | guard components.count >= 3 else { 26 | return nil 27 | } 28 | 29 | let brightness = Float(((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000) 30 | return (brightness > threshold) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIEdgeInsets+Add.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIEdgeInsets+Add.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 31.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIEdgeInsets { 12 | 13 | /// Add number to all edges and return new UIEdgeInsets 14 | /// - Parameter number: CGFloat 15 | /// - Returns: UIEdgeInsets 16 | func add(_ number: CGFloat) -> UIEdgeInsets { 17 | var insets = self 18 | insets.top += number 19 | insets.bottom += number 20 | insets.left += number 21 | insets.right += number 22 | return insets 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIEdgeInsets+NSDirectionalEdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIEdgeInsetsExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 11.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIEdgeInsets { 12 | 13 | /// Transform UIEdgeInsets in to NSDirectionalEdgeInsets 14 | var directionalEdgeInsets: NSDirectionalEdgeInsets { 15 | 16 | return NSDirectionalEdgeInsets(top: top, 17 | leading: left, 18 | bottom: bottom, 19 | trailing: right) 20 | } 21 | 22 | var zeroLeftRightDirectionalEdgeInsets: NSDirectionalEdgeInsets { 23 | 24 | return NSDirectionalEdgeInsets(top: top, 25 | leading: 0, 26 | bottom: bottom, 27 | trailing: 0) 28 | } 29 | 30 | var groupedGridDirectionalEdgeInsets: NSDirectionalEdgeInsets { 31 | 32 | return NSDirectionalEdgeInsets(top: top, 33 | leading: left, 34 | bottom: bottom, 35 | trailing: right) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIImage+SFSymbol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Zalan Mergl on 2022. 06. 01.. 6 | // 7 | 8 | import UIKit 9 | 10 | public extension UIImage { 11 | static func symbolImage(with symbolName: String, configuration: UIImage.Configuration? = nil) -> UIImage? { 12 | if let symbolImage = UIImage(systemName: symbolName, withConfiguration: configuration) { 13 | return symbolImage 14 | } else if let customSymbolImage = UIImage(named: symbolName, in: nil, with: configuration) { 15 | return customSymbolImage 16 | } 17 | 18 | return nil 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UILabelExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UILabelExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UILabel { 12 | 13 | func set(text: DSTextComposer, designableTextColor: DSDesignableTextColor) { 14 | numberOfLines = 0 15 | font = UIFont.systemFont(ofSize: 8) 16 | attributedText = text.attributedString(designableTextColor: designableTextColor) 17 | } 18 | 19 | func setStyle(type: DSTextType, designableTextColor: DSDesignableTextColor) { 20 | self.textColor = type.style.color.getColor(designableTextColor: designableTextColor) 21 | self.font = type.style.font.getFont() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIPageControl+Appearance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIPageControlExtension.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 09.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIPageControl { 12 | 13 | func updateAppearance() { 14 | let appearance = DSAppearance.shared.main 15 | backgroundColor = appearance.primaryView.background 16 | pageIndicatorTintColor = appearance.brandColor.lighten(.C500) 17 | currentPageIndicatorTintColor = appearance.brandColor 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIView+Border.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Border.swift 3 | // 4 | // 5 | // Created by Zalan Mergl on 2022. 04. 14.. 6 | // 7 | 8 | import UIKit 9 | 10 | public extension UIView { 11 | func configureBorder(_ borderStyle: DSViewModelBorderStyle, viewColors: DSDesignableViewColors? = nil) { 12 | switch borderStyle { 13 | case .none: 14 | layer.borderWidth = 0 15 | layer.borderColor = UIColor.clear.cgColor 16 | case .buttonColor: 17 | layer.borderWidth = 2.0 18 | layer.borderColor = viewColors?.button.background.cgColor ?? DSAppearance.shared.main.primaryView.button.background.cgColor 19 | case .brandColor: 20 | layer.borderWidth = 2.0 21 | layer.borderColor = DSAppearance.shared.main.brandColor.cgColor 22 | case .custom(width: let width, color: let color): 23 | layer.borderWidth = width 24 | layer.borderColor = color.cgColor 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIView+Constraints.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Constraints.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 25.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIView { 13 | 14 | func clearConstraints() { 15 | for constraint in self.constraints { 16 | self.removeConstraint(constraint) 17 | } 18 | } 19 | 20 | func equalEdgesTo(view: UIView, insets: UIEdgeInsets = .zero) { 21 | 22 | self.clearConstraints() 23 | 24 | //print(self.constraints) 25 | //print(view.constraints) 26 | 27 | let leftConstraint = view.leftAnchor.constraint(equalTo: self.leftAnchor) 28 | let topConstraint = view.topAnchor.constraint(equalTo: self.topAnchor) 29 | let rightConstraint = view.rightAnchor.constraint(equalTo: self.rightAnchor) 30 | let bottomConstraint = view.bottomAnchor.constraint(equalTo: self.bottomAnchor) 31 | 32 | print(leftConstraint.isActive) 33 | 34 | leftConstraint.constant = insets.left 35 | topConstraint.constant = insets.top 36 | rightConstraint.constant = -insets.right 37 | bottomConstraint.constant = -insets.bottom 38 | 39 | bottomConstraint.priority = UILayoutPriority(rawValue: 999) 40 | 41 | leftConstraint.isActive = true 42 | topConstraint.isActive = true 43 | rightConstraint.isActive = true 44 | bottomConstraint.isActive = true 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/DSKit/Extensions/UIView+EdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Margins.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 04.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Cartography 11 | 12 | extension UIView { 13 | 14 | /// Place self in a subview and add insets from sides 15 | /// - Parameter insets: UIEdgeInsets 16 | /// - Returns: Subview with insets 17 | func subViewWith(insets: UIEdgeInsets) -> UIView { 18 | 19 | let holderView = UIView() 20 | holderView.addSubview(self) 21 | 22 | constrain(self, holderView) { view, holderView in 23 | view.left == holderView.left + insets.left 24 | view.top == holderView.top + insets.top 25 | view.bottom == holderView.bottom - insets.bottom 26 | view.right == holderView.right - insets.right 27 | } 28 | 29 | return holderView 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/DispatchQueue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchQueue.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.11.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension DispatchQueue { 12 | 13 | /// Execute closure after an random delay on main tread 14 | /// - Parameters: 15 | /// - min: Minim delay 16 | /// - max: Maxim delay 17 | /// - closure: Closure to execute 18 | func randomDelay(min: TimeInterval = 0.0, max: TimeInterval = 1.0, _ closure: @escaping () -> Void) { 19 | DispatchQueue.main.asyncAfter(deadline: .now() + Double.random(in: min...max)) { 20 | closure() 21 | } 22 | } 23 | 24 | /// Execute closure on main thread after delay 25 | /// - Parameters: 26 | /// - after: Delay 27 | /// - closure: Closure to execute 28 | func after(_ after: TimeInterval = 0.5, _ closure: @escaping () -> Void) { 29 | DispatchQueue.main.asyncAfter(deadline: .now() + after) { 30 | closure() 31 | } 32 | } 33 | 34 | /// Execute closure on main thread now, used to move executions from other threads to main 35 | /// - Parameter closure: Closure to execute 36 | func now(_ closure: @escaping () -> Void) { 37 | self.after(0.0, closure) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/IAKCacheManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSCacheManager.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 17.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class DSImageCache: NSObject, NSDiscardableContent { 13 | 14 | public var image: UIImage? 15 | 16 | func beginContentAccess() -> Bool { 17 | return true 18 | } 19 | 20 | func endContentAccess() { 21 | 22 | } 23 | 24 | func discardContentIfPossible() { 25 | 26 | } 27 | 28 | func isContentDiscarded() -> Bool { 29 | return false 30 | } 31 | } 32 | 33 | public class DSCacheManager { 34 | 35 | let mapImageCache = NSCache() 36 | 37 | public static let shared = DSCacheManager() 38 | 39 | public init() { 40 | mapImageCache.countLimit = 200 41 | mapImageCache.totalCostLimit = 0 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/NonEquatable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NonEquatable.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 14.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @propertyWrapper 12 | public struct NonEquatable: Equatable, Hashable { 13 | public var wrappedValue: Value 14 | 15 | public init(wrappedValue: Value) { 16 | self.wrappedValue = wrappedValue 17 | } 18 | 19 | public static func == (lhs: NonEquatable, rhs: NonEquatable) -> Bool { 20 | true 21 | } 22 | 23 | public func hash(into hasher: inout Hasher) { 24 | hasher.combine("NonHashable") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/PasswordValidator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PasswordValidator.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 9/21/20. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | // 9 | 10 | import Foundation 11 | import UIKit 12 | 13 | public struct PasswordRule { 14 | let test: (String) -> Bool 15 | } 16 | 17 | public final class PasswordValidator { 18 | 19 | let rules: [PasswordRule] = [ 20 | 21 | PasswordRule(test: { $0.count > 7 }), 22 | PasswordRule(test: { $0.satisfiesRegexp("[a-z]") }), 23 | PasswordRule(test: { $0.satisfiesRegexp("[0-9]") }), 24 | PasswordRule(test: { $0.satisfiesRegexp("[A-Z]") }), 25 | PasswordRule(test: { $0.satisfiesRegexp("[!@#$&()\\-`.+,/\"]*$]") }) 26 | ] 27 | 28 | public func strengthForPassword(_ password: String) -> Double { 29 | return rules.reduce(0) { $0 + ($1.test(password) ? 1 : 0) } 30 | } 31 | 32 | public func colorForPassword(_ password: String) -> UIColor { 33 | 34 | return colorsForStrengths()[strengthForPassword(password)]! 35 | } 36 | 37 | public func colorsForStrengths() -> [Double: UIColor] { 38 | return [ 39 | 0: UIColor(0xD73B00), 40 | 1: UIColor(0xC89100), 41 | 2: UIColor(0xAEAE00), 42 | 3: UIColor(0x97B73E), 43 | 4: UIColor(0x21AF46) 44 | ] 45 | } 46 | } 47 | 48 | internal extension String { 49 | func satisfiesRegexp(_ regexp: String) -> Bool { 50 | return range(of: regexp, options: .regularExpression) != nil 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/PreviewContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreviewContainer.swift 3 | // DSKit+FlowerStore 4 | // 5 | // Created by Borinschi Ivan on 23.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | public struct PreviewContainer: UIViewControllerRepresentable { 13 | 14 | let viewController: UIViewController 15 | let appearance: DSDesignable? 16 | let navigationController: Bool 17 | 18 | public init(VC: UIViewController, _ appearance: DSDesignable? = nil, _ navigationController: Bool = false) { 19 | self.viewController = VC 20 | self.appearance = appearance 21 | self.navigationController = navigationController 22 | } 23 | 24 | public func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIViewController { 25 | 26 | if let appearance = self.appearance { 27 | DSAppearance.shared.main = appearance 28 | } 29 | 30 | if navigationController { 31 | return DSNavigationViewController(rootViewController: viewController) 32 | } else { 33 | return viewController 34 | } 35 | } 36 | 37 | public func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext) { 38 | } 39 | 40 | public typealias UIViewControllerType = UIViewController 41 | } 42 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/Rescale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Rescale.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Rescale { 12 | 13 | typealias RescaleDomain = (lowerBound: Type, upperBound: Type) 14 | 15 | var fromDomain: RescaleDomain 16 | var toDomain: RescaleDomain 17 | 18 | init(from: RescaleDomain, to: RescaleDomain) { 19 | self.fromDomain = from 20 | self.toDomain = to 21 | } 22 | 23 | func interpolate(_ x: Type ) -> Type { 24 | return self.toDomain.lowerBound * (1 - x) + self.toDomain.upperBound * x; 25 | } 26 | 27 | func uninterpolate(_ x: Type) -> Type { 28 | let b = (self.fromDomain.upperBound - self.fromDomain.lowerBound) != 0 ? self.fromDomain.upperBound - self.fromDomain.lowerBound : 1 / self.fromDomain.upperBound; 29 | return (x - self.fromDomain.lowerBound) / b 30 | } 31 | 32 | func rescale(_ x: Type ) -> Type { 33 | return interpolate( uninterpolate(x) ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/DSKit/Helpers/URLOpener.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLOpener.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 9/23/20. 6 | // Copyright © 2020 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class URLOpener { 13 | 14 | typealias CompletionType = ((Bool) -> Swift.Void) 15 | typealias OptionsType = [UIApplication.OpenExternalURLOptionsKey: Any] 16 | 17 | static func open(_ url: URL, options: OptionsType, completion: CompletionType?) { 18 | if #available(iOS 10, *) { 19 | UIApplication.shared.open(url, options: options, completionHandler: completion) 20 | } else { 21 | UIApplication.shared.openURL(url) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/DSKit/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/DSKit/Images.xcassets/mapPlaceholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "mapPlaceholder.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKit/Images.xcassets/mapPlaceholder.imageset/mapPlaceholder.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Sources/DSKit/Images.xcassets/mapPlaceholder.imageset/mapPlaceholder.pdf -------------------------------------------------------------------------------- /Sources/DSKit/Images.xcassets/placeholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "placeholder.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKit/Images.xcassets/placeholder.imageset/placeholder.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Sources/DSKit/Images.xcassets/placeholder.imageset/placeholder.pdf -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSDiffableSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSDiffableSection.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum DSDiffableSection: Hashable { 12 | case section(id: Int) 13 | } 14 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSGallerySection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSGallerySection.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 10.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Extension from DSSection 12 | public final class DSGallerySection: DSSection { 13 | 14 | /// Gallery type 15 | public var galleryType: DSSectionGalleryType 16 | 17 | /// Init Gallery section 18 | /// - Parameters: 19 | /// - viewModels: View models to display in section 20 | /// - type: DSSectionGalleryType 21 | public init(viewModels: [DSViewModel], type: DSSectionGalleryType = .default) { 22 | 23 | self.galleryType = type 24 | super.init() 25 | let appearance = DSAppearance.shared.main 26 | self.viewModels = viewModels 27 | self.type = .gallery(type: type) 28 | 29 | self.insets = UIEdgeInsets(top: appearance.margins, 30 | left: appearance.margins, 31 | bottom: 0, 32 | right: appearance.margins) 33 | 34 | self.interItemSpacing = appearance.interItemSpacing 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSGridSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSGridSection.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 10.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public final class DSGridSection: DSSection { 12 | 13 | /// Grid section 14 | /// - Parameters: 15 | /// - viewModels: View models to display 16 | /// - columns: Number of columns 17 | public init(viewModels: [DSViewModel], columns: Int = 2) { 18 | 19 | super.init() 20 | self.viewModels = viewModels 21 | 22 | let appearance = DSAppearance.shared.main 23 | 24 | insets = UIEdgeInsets(top: appearance.margins, 25 | left: appearance.margins, 26 | bottom: 0, 27 | right: appearance.margins) 28 | 29 | type = .grid(columns: columns) 30 | interItemSpacing = appearance.interItemSpacing 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSection+Count.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSection+Count.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 04.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Array where Element == DSSection { 12 | 13 | var totalViewModelsCount: Int { 14 | return reduce(into: 0) { (count, section) in 15 | count += section.viewModels.count 16 | } 17 | } 18 | 19 | var totalTextFieldViewModelsCount: Int { 20 | return reduce(into: 0) { (count, section) in 21 | count += section.viewModels.reduce(into: 0, { (textFieldsCount, viewModel) in 22 | if viewModel is DSTextFieldVM { 23 | textFieldsCount += 1 24 | } 25 | }) 26 | } 27 | } 28 | } 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSection+Footer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSection+Insets.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 03.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension DSSection { 13 | 14 | /// Headline header with text 15 | /// - Parameter text: String 16 | /// - Returns: Self 17 | @discardableResult func headlineFooter(_ text: String) -> Self { 18 | self.footer = DSLabelVM(.headline, text: text) 19 | return self 20 | } 21 | 22 | /// Subheadline header with text 23 | /// - Parameter text: String 24 | /// - Returns: Self 25 | @discardableResult func subheadlineFooter(_ text: String) -> Self { 26 | self.footer = DSLabelVM(.subheadline, text: text) 27 | return self 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSection+Hash.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSection+Count.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 04.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DSSection { 12 | 13 | // Get diffable hash combined with 14 | // header and footer 15 | var diffableHash: Int { 16 | 17 | var hasher = Hasher() 18 | 19 | if let headerHash = self.headerModelHash { 20 | hasher.combine(headerHash) 21 | } 22 | 23 | if let footerHash = self.footerModelHash { 24 | hasher.combine(footerHash) 25 | } 26 | 27 | hasher.combine(self.type.hashValue) 28 | 29 | return hasher.finalize() 30 | } 31 | 32 | // Get footer hash if exists 33 | var footerModelHash: Int? { 34 | 35 | if let model = footer { 36 | var hasher = Hasher() 37 | hasher.combine(model.hash()) 38 | return hasher.finalize() 39 | } 40 | 41 | return nil 42 | } 43 | 44 | /// Get header hash if exists 45 | var headerModelHash: Int? { 46 | 47 | if let model = header { 48 | var hasher = Hasher() 49 | hasher.combine(model.hash()) 50 | return hasher.finalize() 51 | } 52 | 53 | return nil 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionBackgroundColorPrimaryDecorationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionBackgroundColorPrimaryDecorationView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Combine 11 | 12 | /// Section Background Decoration View 13 | class DSSectionBackgroundColorPrimaryDecorationView: UICollectionReusableView, Subscriber { 14 | 15 | typealias Input = DSDesignable 16 | typealias Failure = Never 17 | 18 | public func receive(subscription: Subscription) { 19 | subscription.request(.unlimited) 20 | } 21 | 22 | public func receive(_ input: Input) -> Subscribers.Demand { 23 | configure() 24 | return .none 25 | } 26 | 27 | public func receive(completion: Subscribers.Completion) { 28 | print("Received completion: \(completion)") 29 | } 30 | 31 | override init(frame: CGRect) { 32 | super.init(frame: frame) 33 | DSAppearance.shared.appearancePublisher.subscribe(self) 34 | configure() 35 | } 36 | required init?(coder: NSCoder) { 37 | fatalError("not implemented") 38 | } 39 | } 40 | 41 | extension DSSectionBackgroundColorPrimaryDecorationView { 42 | 43 | func configure() { 44 | let appearance = DSAppearance.shared.main 45 | backgroundColor = appearance.primaryView.background 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionBackgroundColorSecondaryDecorationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionBackgroundColorSecondaryDecorationView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Combine 11 | 12 | /// Section Background Decoration View 13 | class DSSectionBackgroundColorSecondaryDecorationView: UICollectionReusableView, Subscriber { 14 | 15 | typealias Input = DSDesignable 16 | typealias Failure = Never 17 | 18 | public func receive(subscription: Subscription) { 19 | subscription.request(.unlimited) 20 | } 21 | 22 | public func receive(_ input: Input) -> Subscribers.Demand { 23 | configure() 24 | return .none 25 | } 26 | 27 | public func receive(completion: Subscribers.Completion) { 28 | print("Received completion: \(completion)") 29 | } 30 | 31 | override init(frame: CGRect) { 32 | super.init(frame: frame) 33 | DSAppearance.shared.appearancePublisher.subscribe(self) 34 | configure() 35 | } 36 | required init?(coder: NSCoder) { 37 | fatalError("not implemented") 38 | } 39 | } 40 | 41 | extension DSSectionBackgroundColorSecondaryDecorationView { 42 | 43 | func configure() { 44 | let appearance = DSAppearance.shared.main 45 | backgroundColor = appearance.secondaryView.background 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionBackgroundDecorationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionBackgroundDecorationView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Combine 11 | 12 | /// Section Background Decoration View 13 | class DSSectionBackgroundDecorationView: UICollectionReusableView, Subscriber { 14 | 15 | typealias Input = DSDesignable 16 | typealias Failure = Never 17 | 18 | public func receive(subscription: Subscription) { 19 | subscription.request(.unlimited) 20 | } 21 | 22 | public func receive(_ input: Input) -> Subscribers.Demand { 23 | configure() 24 | return .none 25 | } 26 | 27 | public func receive(completion: Subscribers.Completion) { 28 | print("Received completion: \(completion)") 29 | } 30 | 31 | override init(frame: CGRect) { 32 | super.init(frame: frame) 33 | DSAppearance.shared.appearancePublisher.subscribe(self) 34 | configure() 35 | } 36 | required init?(coder: NSCoder) { 37 | fatalError("not implemented") 38 | } 39 | } 40 | 41 | extension DSSectionBackgroundDecorationView { 42 | 43 | func configure() { 44 | let appearance = DSAppearance.shared.main 45 | backgroundColor = appearance.secondaryView.background 46 | layer.cornerRadius = appearance.secondaryView.cornerRadius 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionBackgroundType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionBackgroundType.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 01.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Section background type 12 | public enum DSSectionBackgroundType { 13 | case `default` 14 | case grouped 15 | case primaryBackground 16 | case secondaryBackground 17 | } 18 | 19 | /// Is section background grouped 20 | extension DSSectionBackgroundType { 21 | var isGrouped: Bool { 22 | self == .grouped 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionGalleryType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionGalleryType.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Gallery section type 12 | public enum DSSectionGalleryType: Equatable, Hashable { 13 | case `default` 14 | case fullWidth 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKit/Sections/DSSectionType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSectionType.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 30.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Section type 12 | public enum DSSectionType: Equatable, Hashable { 13 | case list 14 | case gallery(type: DSSectionGalleryType) 15 | case grid(columns: Int = 2) 16 | } 17 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewControllers/DSViewController/DSViewController+Forms.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewController+Forms.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | public extension DSViewController { 10 | func isCurrentFormValid(_ validate: @escaping (Bool) -> Void) { 11 | collectionView.isCurrentFormValid(validate) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewControllers/DSViewController/DSViewController+Placeholder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewController+Placeholder.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSViewController { 12 | 13 | /// Get placeholder section 14 | /// - Parameters: 15 | /// - image: UIImage 16 | /// - text: String 17 | /// - Returns: DSSection 18 | public func getPlaceholderSection(image: UIImage?, text: String) -> DSSection { 19 | 20 | var viewModels = [DSViewModel]() 21 | 22 | let space = DSSpaceVM(type: .custom(UIScreen.main.bounds.height / 7)) 23 | viewModels.append(space) 24 | 25 | if let image = image { 26 | var imageView = DSImageVM(imageValue: .image(image: image), height: .absolute(70)) 27 | imageView.contentMode = .scaleAspectFit 28 | imageView.imageDisplayStyle = .default 29 | viewModels.append(imageView) 30 | } 31 | 32 | let text = DSLabelVM(.subheadline, text: text, alignment: .center) 33 | viewModels.append(text) 34 | 35 | return viewModels.list() 36 | } 37 | 38 | /// Show placeholder 39 | /// - Parameters: 40 | /// - image: UIImage? 41 | /// - text: String 42 | public func showPlaceholder(image: UIImage? = nil, text: String) { 43 | self.show(content: getPlaceholderSection(image: image, text: text)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSPageControlable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSPageControlable.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol DSPageControlable { 12 | var updatePage: ((Int) -> Void)? {get set} 13 | } 14 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSReusableUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSReusableUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 11.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // Protocol that describes how `DSReusableUIView` should behave 12 | public protocol DSReusableUIView { 13 | 14 | /// This method is called each time a view model will display on screen 15 | /// - Parameter viewModel: DSViewModel 16 | func setUpWith(viewModel: DSViewModel) 17 | 18 | /// This view will be reused each time a view model will display on screen 19 | /// and will be updated with data using `setUpWith(viewModel: DSViewModel)` function 20 | var view: UIView {get} 21 | } 22 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSSideView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSupplementaryView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 10.03.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public struct DSSideView: Equatable, Hashable { 13 | 14 | var viewModel: DSViewModel 15 | 16 | public init(view: DSViewModel) { 17 | self.viewModel = view 18 | } 19 | 20 | public static func == (lhs: DSSideView, rhs: DSSideView) -> Bool { 21 | return lhs.viewModel.isEqual(to: rhs.viewModel) 22 | } 23 | 24 | public func hash(into hasher: inout Hasher) { 25 | hasher.combine(viewModel.hash()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelBorderStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelBorderStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model display style 12 | public enum DSViewModelBorderStyle: Equatable, Hashable { 13 | 14 | case none 15 | case buttonColor 16 | case brandColor 17 | case custom(width: CGFloat, color: UIColor) 18 | 19 | /// Raw value 20 | var rawValue: String { 21 | 22 | switch self { 23 | case .none: 24 | return "none" 25 | case .buttonColor: 26 | return "buttonColor" 27 | case .brandColor: 28 | return "brandColor" 29 | case .custom(let width, let color): 30 | return "\(width)\(color.dsDescription)" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelColorStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelColorStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model display style 12 | public enum DSViewModelColorStyle: Equatable, Hashable { 13 | 14 | case `default` 15 | case primary 16 | case secondary 17 | case custom(DSDesignableViewColors) 18 | 19 | /// Raw value 20 | var rawValue: String { 21 | switch self { 22 | case .primary: 23 | return "primary" 24 | case .secondary: 25 | return "secondary" 26 | case .custom(_): 27 | return "custom" 28 | case .default: 29 | return "default" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelCornersStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelCornersStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model corner style 12 | public enum DSViewModelCornersStyle: Equatable, Hashable { 13 | 14 | case `default` 15 | case zero 16 | case custom(CGFloat) 17 | 18 | /// Raw value 19 | var rawValue: String { 20 | switch self { 21 | case .zero: 22 | return "zero" 23 | case .default: 24 | return "default" 25 | case .custom(let cornerRadius): 26 | return "custom_\(cornerRadius)" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelDataSource.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Used to generate UICollectionViewDiffableDataSource 12 | struct DSViewModelDataSource: Hashable, Equatable { 13 | 14 | func hash(into hasher: inout Hasher) { 15 | hasher.combine(model.hash()) 16 | } 17 | 18 | static func == (lhs: DSViewModelDataSource, rhs: DSViewModelDataSource) -> Bool { 19 | lhs.model.isEqual(to: rhs.model) 20 | } 21 | 22 | let model: DSViewModel 23 | } 24 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelDisplayStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelDisplayStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model display style 12 | public enum DSViewModelDisplayStyle: Equatable, Hashable { 13 | 14 | case `default` //Edge to edge with no margins 15 | case grouped(inSection: Bool) // DSDesignable groupMargins will be applied to each side in dependence in which context this view model is shown 16 | 17 | /// Raw value 18 | var rawValue: String { 19 | switch self { 20 | case .default: 21 | return "Default" 22 | case .grouped(inSection: let inSection): 23 | if inSection { 24 | return "SectionGrouped" 25 | } else { 26 | return "Grouped" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelShadowStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelShadowStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model display style 12 | public enum DSViewModelShadowStyle: Equatable, Hashable { 13 | 14 | case none 15 | case small 16 | case light 17 | 18 | /// Raw value 19 | var rawValue: String { 20 | 21 | switch self { 22 | case .none: 23 | return "none" 24 | case .small: 25 | return "small" 26 | case .light: 27 | return "light" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DSViewModelStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelStyle.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 21.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// View model display style 12 | public struct DSViewModelStyle: Equatable, Hashable { 13 | 14 | public var colorStyle: DSViewModelColorStyle = .default 15 | public var cornerStyle: DSViewModelCornersStyle = .default 16 | public var borderStyle: DSViewModelBorderStyle = .none 17 | public var shadowStyle: DSViewModelShadowStyle = .none 18 | public var displayStyle: DSViewModelDisplayStyle = .default 19 | 20 | public init(colorStyle: DSViewModelColorStyle = .default, 21 | cornerStyle: DSViewModelCornersStyle = .default, 22 | borderStyle: DSViewModelBorderStyle = .none, 23 | shadowStyle: DSViewModelShadowStyle = .none, 24 | displayStyle: DSViewModelDisplayStyle = .default) { 25 | 26 | self.colorStyle = colorStyle 27 | self.cornerStyle = cornerStyle 28 | self.borderStyle = borderStyle 29 | self.shadowStyle = shadowStyle 30 | self.displayStyle = displayStyle 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/DefaultReusableUIViewView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultReusableUIViewView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class DefaultReusableUIViewView: UIView, DSReusableUIView { 12 | 13 | public var view: UIView { 14 | self 15 | } 16 | 17 | public func setUpWith(viewModel: DSViewModel) { 18 | print("Please implement getUIViewRepresentation() protocol method for \(viewModel)") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/Extensions/DSViewModel+PrepareToDisplay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModel+SideViews.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 16.03.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSViewModel { 12 | 13 | mutating func prepareToDisplay() { 14 | 15 | if var vm = self.rightSideView?.viewModel { 16 | vm.style.displayStyle = self.style.displayStyle 17 | self.rightSideView = DSSideView(view: vm) 18 | } 19 | 20 | if var vm = self.leftSideView?.viewModel { 21 | vm.style.displayStyle = self.style.displayStyle 22 | self.leftSideView = DSSideView(view: vm) 23 | } 24 | 25 | if var vm = self.topSideView?.viewModel { 26 | vm.style.displayStyle = self.style.displayStyle 27 | self.topSideView = DSSideView(view: vm) 28 | } 29 | 30 | if var vm = self.bottomSideView?.viewModel { 31 | vm.style.displayStyle = self.style.displayStyle 32 | self.bottomSideView = DSSideView(view: vm) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/Extensions/DSViewModel+isEqual.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModel+isEqual.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension DSViewModel { 12 | 13 | /// Check if view model is equal to other view model 14 | /// - Parameter object: DSViewModel 15 | /// - Returns: Bool 16 | func isEqual(to object: DSViewModel) -> Bool { 17 | return false 18 | } 19 | } 20 | 21 | public extension Array where Element == DSViewModel { 22 | 23 | /// Check if array of view model are equal to other array of view models 24 | /// - Parameter array: [DSViewModel] 25 | /// - Returns: Bool 26 | func isEqual(to array: [DSViewModel]) -> Bool { 27 | 28 | if self.count != array.count { 29 | return false 30 | } 31 | 32 | for (index, element) in self.enumerated() { 33 | let compareTo = array[index] 34 | if !element.isEqual(to: compareTo) { 35 | return false 36 | } 37 | } 38 | 39 | return true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModelProtocol/Extensions/DSViewModelDisplayStyle+UIEdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSViewModelDisplayStyle+UIEdgeInsets.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 02.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension DSViewModelDisplayStyle { 12 | 13 | /// Get view insets based on DSViewModelDisplayStyle 14 | /// - Returns: UIEdgeInsets 15 | func viewInsets() -> UIEdgeInsets { 16 | 17 | switch self { 18 | case .default: 19 | return .zero 20 | case .grouped(inSection: let inSection): 21 | 22 | if inSection { 23 | return .zero 24 | } else { 25 | return DSAppearance.shared.main.groupMargins.edgeInsets 26 | } 27 | } 28 | } 29 | 30 | /// Get view insets when this view model is displayed as supplementary view 31 | /// - Parameters: 32 | /// - section: DSSection 33 | /// - kind: String, supplementary view kind 34 | /// - Returns: UIEdgeInsets 35 | func supplementaryViewInsets(section: DSSection, kind: String) -> UIEdgeInsets { 36 | 37 | if kind == UICollectionView.elementKindSectionHeader { 38 | return UIEdgeInsets(top: DSAppearance.shared.main.margins, left: 0, bottom: -5, right: 0) 39 | } else if kind == UICollectionView.elementKindSectionFooter { 40 | return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 41 | } 42 | 43 | return .zero 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Action/DSActionVM+TopContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSActionVM+LeftContent.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 03.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension DSActionVM { 12 | 13 | /// Set action top image with UIImage 14 | /// - Parameters: 15 | /// - image: UIImage 16 | /// - height: DSImageHeight 17 | /// - contentMode: DSImageContentMode 18 | mutating func topImage(image: UIImage?, 19 | height: DSImageHeight = .unknown, 20 | contentMode: DSImageContentMode = .scaleAspectFill) { 21 | 22 | self.topImage = DSImageContent.image(image: image) 23 | self.topImageContentMode = contentMode 24 | self.topImageHeight = height 25 | } 26 | 27 | /// Set action top image with URL? 28 | /// - Parameters: 29 | /// - url: URL? 30 | /// - height: DSImageHeight 31 | /// - contentMode: DSImageContentMode 32 | mutating func topImage(url: URL?, 33 | height: DSImageHeight = .unknown, 34 | contentMode: DSImageContentMode = .scaleAspectFill) { 35 | 36 | self.topImage = DSImageContent.imageURL(url: url) 37 | self.topImageContentMode = contentMode 38 | self.topImageHeight = height 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/ActiveText/DSActiveTextUIView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Button/DSButtonUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSButtonUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 11.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSButtonUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var button: ImoUIButton! 14 | 15 | var viewModel: DSButtonVM? 16 | 17 | public var view: UIView { self } 18 | 19 | public func setUpWith(viewModel: DSViewModel) { 20 | 21 | guard let viewModel = viewModel as? DSButtonVM else { 22 | return 23 | } 24 | 25 | self.viewModel = viewModel 26 | update(viewModel: viewModel) 27 | } 28 | 29 | /// This method is called each time a copy of DSButtonUIView is prepared to be displayed on screen 30 | /// - Parameter viewModel: DSButtonVM 31 | func update(viewModel: DSButtonVM) { 32 | 33 | button.setUpWith(viewModel: viewModel) 34 | 35 | /// Handle did tap on button 36 | button.button.didTouchUpInside = { [weak self] _ in 37 | 38 | guard let _self = self else { 39 | return 40 | } 41 | 42 | _self.viewModel?.didTap?(viewModel) 43 | } 44 | } 45 | 46 | override func awakeFromNib() { 47 | super.awakeFromNib() 48 | backgroundColor = .clear 49 | button.backgroundColor = .clear 50 | } 51 | 52 | class func instanceFromNib() -> DSButtonUIView { 53 | let view: DSButtonUIView = initFromNib() 54 | return view 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Color/DSColorUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSColorUIView.swift 3 | // DSKit Explorer 4 | // 5 | // Created by Borinschi Ivan on 18.03.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSColorUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var colorView: UIView! 14 | 15 | /// DSReusableUIView protocol 16 | public var view: UIView { self } 17 | 18 | /// Set up with view model is called each time when a copy of 19 | /// this uiview is prepared to be displayed on the screen 20 | /// - Parameter viewModel: DSViewModel 21 | public func setUpWith(viewModel: DSViewModel) { 22 | 23 | guard let viewModel = viewModel as? DSColorVM else { return } 24 | update(viewModel: viewModel) 25 | } 26 | 27 | /// Update view with view model 28 | /// - Parameter viewModel: DSColorVM 29 | func update(viewModel: DSColorVM) { 30 | colorView.backgroundColor = viewModel.color 31 | colorView.layer.cornerRadius = viewModel.viewColors().cornerRadius 32 | colorView.clipsToBounds = true 33 | colorView.layer.borderWidth = 1.5 34 | colorView.layer.borderColor = DSAppearance.shared.main.secondaryView.background.cgColor 35 | } 36 | 37 | override func awakeFromNib() { 38 | super.awakeFromNib() 39 | backgroundColor = .clear 40 | } 41 | 42 | class func instanceFromNib() -> DSColorUIView { 43 | let view: DSColorUIView = initFromNib() 44 | return view 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Label/DSLabelUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSLabelUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 15.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSLabelUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var textLabel: UILabel! 14 | var appearance = DSAppearance.shared.main 15 | var fonts = DSAppearance.shared.main.fonts 16 | 17 | public var view: UIView { self } 18 | 19 | public func setUpWith(viewModel: DSViewModel) { 20 | 21 | guard let viewModel = viewModel as? DSLabelVM else { 22 | return 23 | } 24 | 25 | update(viewModel: viewModel) 26 | } 27 | 28 | func update(viewModel: DSLabelVM) { 29 | textLabel.set(text: viewModel.textComposer, designableTextColor: viewModel.viewColors().text) 30 | } 31 | 32 | override func awakeFromNib() { 33 | super.awakeFromNib() 34 | backgroundColor = .clear 35 | } 36 | 37 | class func instanceFromNib() -> DSLabelUIView { 38 | let view: DSLabelUIView = initFromNib() 39 | return view 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Page/DSPageUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSWalkthroughPageUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSPageUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var collectionView: DSCollectionView! 14 | var appearance = DSAppearance.shared.main 15 | 16 | public var view: UIView { self } 17 | 18 | public func setUpWith(viewModel: DSViewModel) { 19 | 20 | guard let viewModel = viewModel as? DSPageVM else { return } 21 | update(viewModel: viewModel) 22 | } 23 | 24 | func update(viewModel: DSPageVM) { 25 | 26 | let section = viewModel.viewModels.list() 27 | section.insets = viewModel.contentInsets 28 | collectionView.show(content: [section], animated: false) 29 | collectionView.backgroundColor = viewModel.viewColors().background 30 | collectionView.view.backgroundColor = viewModel.viewColors().background 31 | collectionView.view.backgroundColor = .clear 32 | collectionView.view.bounces = false 33 | } 34 | 35 | override func awakeFromNib() { 36 | super.awakeFromNib() 37 | backgroundColor = .clear 38 | } 39 | 40 | class func instanceFromNib() -> DSPageUIView { 41 | let view: DSPageUIView = initFromNib() 42 | return view 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Separator/DSSeparatorUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSeparatorUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 18.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSSeparatorUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var separatorView: UIView! 14 | @IBOutlet weak var leftSpace: NSLayoutConstraint! 15 | @IBOutlet weak var rightSpace: NSLayoutConstraint! 16 | public var view: UIView { self } 17 | 18 | let appearance = DSAppearance.shared.main 19 | 20 | public func setUpWith(viewModel: DSViewModel) { 21 | guard let viewModel = viewModel as? DSSeparatorVM else { return } 22 | update(viewModel: viewModel) 23 | } 24 | 25 | func update(viewModel: DSSeparatorVM) { 26 | 27 | backgroundColor = .clear 28 | separatorView.backgroundColor = viewModel.viewColors().separator 29 | leftSpace.constant = 0 30 | rightSpace.constant = 0 31 | } 32 | 33 | class func instanceFromNib() -> DSSeparatorUIView { 34 | let view: DSSeparatorUIView = initFromNib() 35 | return view 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Space/DSSpaceUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSpaceUIView.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 18.12.2020. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSSpaceUIView: UIView, DSReusableUIView { 12 | 13 | public var view: UIView { self } 14 | @IBOutlet weak var spaceView: UIView! 15 | 16 | public func setUpWith(viewModel: DSViewModel) { 17 | guard let viewModel = viewModel as? DSSpaceVM else { return } 18 | update(viewModel: viewModel) 19 | } 20 | 21 | func update(viewModel: DSSpaceVM) { 22 | spaceView.backgroundColor = .clear 23 | } 24 | 25 | class func instanceFromNib() -> DSSpaceUIView { 26 | let view: DSSpaceUIView = initFromNib() 27 | return view 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/Switch/DSSwitchUIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSSwitchUIView.swift 3 | // DSKit Explorer 4 | // 5 | // Created by Borinschi Ivan on 19.03.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DSSwitchUIView: UIView, DSReusableUIView { 12 | 13 | @IBOutlet weak var switchView: UISwitch! 14 | /// DSReusableUIView protocol 15 | public var view: UIView { self } 16 | 17 | var viewModel: DSSwitchVM? 18 | 19 | /// Set up with view model is called each time when a copy of 20 | /// this uiview is prepared to be displayed on the screen 21 | /// - Parameter viewModel: DSViewModel 22 | public func setUpWith(viewModel: DSViewModel) { 23 | 24 | guard let viewModel = viewModel as? DSSwitchVM else { return } 25 | self.viewModel = viewModel 26 | update(viewModel: viewModel) 27 | } 28 | 29 | /// Update view with view model 30 | /// - Parameter viewModel: DSSwitchVM 31 | func update(viewModel: DSSwitchVM) { 32 | switchView.isOn = viewModel.isOn 33 | switchView.onTintColor = DSAppearance.shared.main.semanticGreenColor 34 | } 35 | 36 | override func awakeFromNib() { 37 | super.awakeFromNib() 38 | backgroundColor = .clear 39 | } 40 | 41 | @IBAction func didUpdate(_ sender: Any) { 42 | 43 | guard let viewModel = self.viewModel else { 44 | return 45 | } 46 | 47 | viewModel.didUpdate?(self.switchView.isOn) 48 | } 49 | 50 | class func instanceFromNib() -> DSSwitchUIView { 51 | let view: DSSwitchUIView = initFromNib() 52 | return view 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Sources/DSKit/ViewModels/TextField/DSTextFieldVM+Validations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSTextFieldVM+Validations.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 04.02.2021. 6 | // Copyright © 2021 Borinschi Ivan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension DSTextFieldVM { 12 | 13 | /// Is text valid 14 | /// - Parameters: 15 | /// - text: Text to validate 16 | /// - validateEmptyTextField: Should result be valid is textfield is empty 17 | /// - validate: validation result closure 18 | func isValid(text: String?, validateEmptyTextField: Bool,_ validate: @escaping (Bool) -> Void) { 19 | 20 | // We will use user defined validation 21 | if let userValidation = self.handleValidation { 22 | 23 | // Send current value to user validation 24 | validate(userValidation(text)) 25 | 26 | } else { 27 | 28 | // If text is empty and validateEmptyTextField == true 29 | // then validate true 30 | if text == "" && validateEmptyTextField { 31 | validate(true) 32 | 33 | } else if validator.isValidMinimLength(validateMinimumLength, text) && 34 | validator.isValidMaximLength(validateMaximumLength, text) && 35 | validator.validate(string: text, pattern: validationPattern) && 36 | validator.isValidWhiteSpaces(string: text) { 37 | 38 | validate(true) 39 | 40 | } else { 41 | validate(false) 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/DSKitCalendar/DSDayLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HCDayLabel.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 23.12.2020. 6 | // 7 | 8 | import UIKit 9 | import HorizonCalendar 10 | import DSKit 11 | 12 | struct DSDayLabel: CalendarItemViewRepresentable { 13 | 14 | /// Properties that are set once when we initialize the view. 15 | struct InvariantViewProperties: Hashable { 16 | let font: UIFont 17 | var textColor: UIColor 18 | var backgroundColor: UIColor 19 | var alpha: CGFloat 20 | } 21 | 22 | /// Properties that will vary depending on the particular date being displayed. 23 | struct ViewModel: Equatable { 24 | let day: Day 25 | } 26 | 27 | static func makeView(withInvariantViewProperties invariantViewProperties: InvariantViewProperties) -> UILabel { 28 | 29 | let label = UILabel() 30 | 31 | label.backgroundColor = invariantViewProperties.backgroundColor 32 | label.font = invariantViewProperties.font 33 | label.textColor = invariantViewProperties.textColor 34 | 35 | label.textAlignment = .center 36 | label.clipsToBounds = true 37 | label.layer.cornerRadius = DSAppearance.shared.main.secondaryView.cornerRadius 38 | label.alpha = invariantViewProperties.alpha 39 | 40 | return label 41 | } 42 | 43 | static func setViewModel(_ viewModel: ViewModel, on view: UILabel) { 44 | view.text = "\(viewModel.day.day)" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/DSKitCalendar/DSDayOfWeekLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HCDayLabel.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 23.12.2020. 6 | // 7 | 8 | import UIKit 9 | import HorizonCalendar 10 | 11 | struct DSDayOfWeekLabel: CalendarItemViewRepresentable { 12 | 13 | /// Properties that are set once when we initialize the view. 14 | struct InvariantViewProperties: Hashable { 15 | let font: UIFont 16 | var textColor: UIColor 17 | } 18 | 19 | /// Properties that will vary depending on the particular date being displayed. 20 | struct ViewModel: Equatable { 21 | let month: Month? 22 | let day: Int 23 | } 24 | 25 | static func makeView(withInvariantViewProperties invariantViewProperties: InvariantViewProperties) -> UILabel { 26 | 27 | let label = UILabel() 28 | label.font = invariantViewProperties.font 29 | label.textColor = invariantViewProperties.textColor 30 | 31 | label.textAlignment = .center 32 | label.clipsToBounds = true 33 | 34 | return label 35 | } 36 | 37 | static func setViewModel(_ viewModel: ViewModel, on view: UILabel) { 38 | 39 | guard var components = viewModel.month?.components else { 40 | return 41 | } 42 | 43 | components.day = viewModel.day 44 | 45 | let date = Calendar.current.date(from: components) 46 | 47 | guard let text = date?.stringFormattedWeekDay(dateStyle: .short) else { 48 | return 49 | } 50 | 51 | view.text = text 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/DSKitCalendar/DSMonthLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HCDayLabel.swift 3 | // DSKit 4 | // 5 | // Created by Borinschi Ivan on 23.12.2020. 6 | // 7 | 8 | import HorizonCalendar 9 | import UIKit 10 | 11 | struct DSMonthLabel: CalendarItemViewRepresentable { 12 | 13 | /// Properties that are set once when we initialize the view. 14 | struct InvariantViewProperties: Hashable { 15 | let font: UIFont 16 | var textColor: UIColor 17 | } 18 | 19 | /// Properties that will vary depending on the particular date being displayed. 20 | struct ViewModel: Equatable { 21 | let month: Month 22 | } 23 | 24 | static func makeView(withInvariantViewProperties invariantViewProperties: InvariantViewProperties) -> UILabel { 25 | 26 | let label = UILabel() 27 | label.font = invariantViewProperties.font 28 | label.textColor = invariantViewProperties.textColor 29 | 30 | label.textAlignment = .left 31 | label.clipsToBounds = true 32 | 33 | return label 34 | } 35 | 36 | static func setViewModel(_ viewModel: ViewModel, on view: UILabel) { 37 | 38 | let date = Calendar.current.date(from: viewModel.month.components) 39 | 40 | guard let text = date?.stringFormattedMonth() else { 41 | return 42 | } 43 | 44 | view.text = text 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/Models/DSAddress.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FakeAddress.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | import MapKit 10 | 11 | public struct DSAddress { 12 | 13 | public let address: String 14 | public let coordinate: CLLocationCoordinate2D 15 | public var title: String { 16 | self.address.components(separatedBy: ",").first ?? address 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/Models/DSPerson.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Person.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct DSPerson { 11 | public let name: String 12 | public let description: String 13 | public var image: URL? 14 | public var email: String 15 | public var phone: String 16 | } 17 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+AdditionalProducts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Flowers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let balloons = URL(string: "https://images.unsplash.com/photo-1554719805-92eb757a4ca4?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 13 | 14 | static let bunny = URL(string: "https://images.unsplash.com/photo-1562224780-ba39856ecadd?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1952&q=80") 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Cards.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Flowers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let standardCard = URL(string: "https://images.unsplash.com/photo-1566125882500-87e10f726cdc?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1867&q=80") 13 | 14 | static let cardLoveIt = URL(string: "https://images.unsplash.com/photo-1579532649051-ed5208863cd9?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 15 | 16 | static let cardForYou = URL(string: "https://images.unsplash.com/photo-1535381273077-21e00c27b1b7?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1867&q=80") 17 | } 18 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Echeveria.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Echeveria.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let echeveriaPink = URL(string: "https://images.unsplash.com/photo-1587788793142-fe98e1521131?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=975&q=80") 13 | 14 | static let echeveriaGreen = URL(string: "https://images.unsplash.com/photo-1562536404-7664b90d738e?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1951&q=80") 15 | } 16 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Flowers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Flowers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let flowersBirthday = URL(string: "https://images.unsplash.com/photo-1607215121535-c52a7957bb18?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 13 | 14 | static let flowersValentines = URL(string: "https://images.unsplash.com/photo-1557872048-d2c03143cabc?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 15 | 16 | static let flowersJust = URL(string: "https://images.unsplash.com/photo-1559533914-a0849c51e503?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Hydrangea.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Echeveria.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let hydrangeaPink = URL(string: "https://images.unsplash.com/photo-1438268056692-f9603ecc1def?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80") 13 | 14 | static let hydrangeaGreen = URL(string: "https://images.unsplash.com/photo-1528750164675-112c3f715fd9?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1949&q=80") 15 | 16 | static let hydrangeaBlue = URL(string: "https://images.unsplash.com/photo-1536349528643-35e757a105d0?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80") 17 | 18 | static let hydrangeaRed = URL(string: "https://images.unsplash.com/photo-1475873326779-99eac8da25b0?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=933&q=80") 19 | } 20 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Jeans.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let jeansOnBlackBg = URL(string: "https://images.pexels.com/photos/1598507/pexels-photo-1598507.jpeg?cs=srgb&dl=pexels-mnz-1598507.jpg&fm=jpg") 13 | 14 | static let jeansPairs = URL(string: "https://images.pexels.com/photos/4210863/pexels-photo-4210863.jpeg?cs=srgb&dl=pexels-karolina-grabowska-4210863.jpg&fm=jpg") 15 | 16 | static let pantsTrack = URL(string: "https://images.pexels.com/photos/5067705/pexels-photo-5067705.jpeg?cs=srgb&dl=pexels-anna-shvets-5067705.jpg&fm=jpg") 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Roses.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Roses.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let rosesYellow = URL(string: "https://images.pexels.com/photos/2342264/pexels-photo-2342264.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") 13 | 14 | static let rosesPink = URL(string: "https://images.pexels.com/photos/2512281/pexels-photo-2512281.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500") 15 | 16 | static let rosesRed = URL(string: "https://images.unsplash.com/photo-1552174965-c6616f62fc4f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80") 17 | 18 | static let rosesMulticolor = URL(string: "https://images.unsplash.com/photo-1584447310566-bb4d13797f36?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Njh8fHJvc2VzJTIwYm91cXVldHxlbnwwfHwwfA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60") 19 | 20 | static let rosesWhite = URL(string: "https://images.unsplash.com/photo-1571086803179-00ab0eaa6e02?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1951&q=80") 21 | } 22 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Shirts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let shirtsThreePairs = URL(string: "https://images.unsplash.com/photo-1602810318383-e386cc2a3ccf?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MXx8c2hpcnRzfGVufDB8fDB8&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60") 13 | } 14 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Shoes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let shoesThreePairs = URL(string: "https://images.pexels.com/photos/267301/pexels-photo-267301.jpeg?cs=srgb&dl=pexels-pixabay-267301.jpg&fm=jpg") 13 | 14 | static let purpleShoes = URL(string: "https://images.pexels.com/photos/2351858/pexels-photo-2351858.jpeg?cs=srgb&dl=pexels-lorena-mart%C3%ADnez-2351858.jpg&fm=jpg") 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Sneakers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let sneakersWhiteOnYellowBg = URL(string: "https://images.pexels.com/photos/2421374/pexels-photo-2421374.jpeg?cs=srgb&dl=pexels-hoang-loc-2421374.jpg&fm=jpg") 13 | 14 | static let sneakersBlackOnBlueBg = URL(string: "https://images.pexels.com/photos/1478442/pexels-photo-1478442.jpeg?cs=srgb&dl=pexels-ray-piedra-1478442.jpg&fm=jpg") 15 | 16 | static let sneakersThreePairs = URL(string: "https://images.pexels.com/photos/2300334/pexels-photo-2300334.jpeg?cs=srgb&dl=pexels-adrian-dorobantu-2300334.jpg&fm=jpg") 17 | 18 | static let sneakersOnWhiteBg = URL(string: "https://images.pexels.com/photos/1858404/pexels-photo-1858404.jpeg?cs=srgb&dl=pexels-athena-1858404.jpg&fm=jpg") 19 | 20 | static let sneakersOnBlackBg = URL(string: "https://images.pexels.com/photos/582485/pexels-photo-582485.jpeg?cs=srgb&dl=pexels-karol-d-582485.jpg&fm=jpg") 21 | 22 | static let sneakersNeon = URL(string: "https://images.pexels.com/photos/6698232/pexels-photo-6698232.jpeg?cs=srgb&dl=pexels-smith-major-6698232.jpg&fm=jpg") 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+TShirts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | static let tShirtGirlOnYellowBg = URL(string: "https://images.pexels.com/photos/761963/pexels-photo-761963.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") 12 | } 13 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+TopFlowers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Roses.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let topFlowers1 = URL(string: "https://images.unsplash.com/photo-1510894399130-57dfa8dcc45d?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1875&q=80") 13 | 14 | static let topFlowers2 = URL(string: "https://images.unsplash.com/photo-1452827073306-6e6e661baf57?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1867&q=80") 15 | 16 | static let topFlowers3 = URL(string: "https://images.unsplash.com/photo-1508369311886-278fdb148796?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1973&q=80") 17 | } 18 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Tulips.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Tulips.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let tulipsMulticolor = URL(string: "https://images.pexels.com/photos/350349/pexels-photo-350349.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") 13 | 14 | static let tulipsRed = URL(string: "https://images.pexels.com/photos/2058499/pexels-photo-2058499.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") 15 | 16 | static let tulipsYellow = URL(string: "https://images.unsplash.com/photo-1587000202890-07c8338c6e34?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1300&q=80") 17 | 18 | static let tulipsWhite = URL(string: "https://images.unsplash.com/photo-1581490418272-51f08b7b7418?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80") 19 | 20 | static let tulipsSpecial = URL(string: "https://images.unsplash.com/photo-1522585330351-9d852961c300?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1867&q=80") 21 | } 22 | -------------------------------------------------------------------------------- /Sources/DSKitFakery/URL+Watches.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Sneakers.swift 3 | // DSKit+Fakery 4 | // 5 | // Created by Borinschi Ivan on 27.01.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension URL { 11 | 12 | static let watchesFernandoAcros = URL(string: "https://images.pexels.com/photos/190819/pexels-photo-190819.jpeg?cs=srgb&dl=pexels-fernando-arcos-190819.jpg&fm=jpg") 13 | 14 | static let watchesOnYellowBg = URL(string: "https://images.pexels.com/photos/277390/pexels-photo-277390.jpeg?cs=srgb&dl=pexels-pixabay-277390.jpg&fm=jpg") 15 | 16 | static let blazers = URL(string: "https://images.pexels.com/photos/3555456/pexels-photo-3555456.jpeg?cs=srgb&dl=pexels-mikotoraw-3555456.jpg&fm=jpg") 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Templates/ViewModelTemplates/ViewModel.xctemplate/DS___FILEBASENAME___UIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import UIKit 10 | import DSKit 11 | 12 | final class DS___VARIABLE_moduleName___UIView: UIView, DSReusableUIView { 13 | 14 | /// DSReusableUIView protocol 15 | public var view: UIView { self } 16 | 17 | /// Set up with view model is called each time when a copy of 18 | /// this UI View is prepared to be displayed on the screen 19 | /// - Parameter viewModel: DSViewModel 20 | public func setUpWith(viewModel: DSViewModel) { 21 | 22 | guard let viewModel = viewModel as? DS___VARIABLE_moduleName___VM else { return } 23 | update(viewModel: viewModel) 24 | } 25 | 26 | /// Update view with view model 27 | /// - Parameter viewModel: DS___VARIABLE_moduleName___VM 28 | func update(viewModel: DS___VARIABLE_moduleName___VM) { 29 | 30 | // DO YOUR WORK HERE 31 | // THIS IS A REUSABLE VIEW 32 | // THIS METHOD IS CALLED EVERY-TIME THIS VIEW IS DISPLAYED ON SCREEN 33 | } 34 | 35 | class func instanceFromNib() -> DS___VARIABLE_moduleName___UIView { 36 | let view: DS___VARIABLE_moduleName___UIView = initFromNib() 37 | return view 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Templates/ViewModelTemplates/ViewModel.xctemplate/DS___FILEBASENAME___UIView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Templates/ViewModelTemplates/ViewModel.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Templates/ViewModelTemplates/ViewModel.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Templates/ViewModelTemplates/ViewModel.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imodeveloperlab/dskit/c9810f80d2a1052aa3bd999e2d91eac1b0d5b1e9/Templates/ViewModelTemplates/ViewModel.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Templates/ViewModelTemplates/install.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | abort() 4 | { 5 | echo >&2 ' 6 | *************** 7 | *** ABORTED *** 8 | *************** 9 | ' 10 | echo "An error occurred. Exiting..." >&2 11 | exit 1 12 | } 13 | 14 | trap 'abort' 0 15 | set -e 16 | 17 | BASEDIR=$HOME 18 | TEMPLATESDIR1=~/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File\ Templates 19 | TEMPLATESDIR2=~/Downloads/Xcode.app/Contents/Developer/Library/Xcode/Templates/File\ Templates 20 | FULLTEMPLATESDIR1="$TEMPLATESDIR1/DSKit" 21 | FULLTEMPLATESDIR2="$TEMPLATESDIR2/DSKit" 22 | 23 | echo "Templates will be installed" 24 | 25 | if [ -d "${FULLTEMPLATESDIR1}" ]; then 26 | rm -r "${FULLTEMPLATESDIR1}" 27 | fi 28 | 29 | if [ -d "${FULLTEMPLATESDIR2}" ]; then 30 | rm -r "${FULLTEMPLATESDIR2}" 31 | fi 32 | 33 | mkdir -p "${FULLTEMPLATESDIR1}" 34 | cp -r *.xctemplate "${FULLTEMPLATESDIR1}" 35 | 36 | mkdir -p "${FULLTEMPLATESDIR2}" 37 | cp -r *.xctemplate "${FULLTEMPLATESDIR2}" 38 | 39 | trap : 0 40 | 41 | echo >&2 ' 42 | *********************************************** 43 | *** DSKit templates, successfully installed *** 44 | *********************************************** 45 | ' 46 | -------------------------------------------------------------------------------- /Tests/DSKitTests/DSKitTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DSKit 3 | 4 | final class DSKitTests: XCTestCase { 5 | func testExample() throws { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertNotNil(nil, "Oh") 10 | } 11 | } 12 | --------------------------------------------------------------------------------