├── Assets
└── Readme
│ ├── spm-install-preview.png
│ └── Elements
│ ├── NativePlayPauseCompactButton.svg
│ ├── NativeSmallActionButton.svg
│ ├── NativeAvatarView.svg
│ └── NativeLargeActionButton.svg
├── Example App
├── tvOS Example
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── App Icon & Top Shelf Image.brandassets
│ │ │ ├── App Icon.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Middle.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ │ ├── App Icon - App Store.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Middle.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ │ ├── Top Shelf Image.imageset
│ │ │ └── Contents.json
│ │ │ ├── Top Shelf Image Wide.imageset
│ │ │ └── Contents.json
│ │ │ └── Contents.json
│ ├── Info.plist
│ └── LaunchScreen.storyboard
├── iOS Example
│ ├── App
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ └── AppDelegate.swift
│ ├── Scenes
│ │ └── RootController.swift
│ └── Info.plist
├── watchOS Example Extension
│ ├── ExtensionDelegate.swift
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── Complication.complicationset
│ │ │ ├── Graphic Bezel.imageset
│ │ │ └── Contents.json
│ │ │ ├── Graphic Corner.imageset
│ │ │ └── Contents.json
│ │ │ ├── Graphic Circular.imageset
│ │ │ └── Contents.json
│ │ │ ├── Graphic Large Rectangular.imageset
│ │ │ └── Contents.json
│ │ │ ├── Circular.imageset
│ │ │ └── Contents.json
│ │ │ ├── Modular.imageset
│ │ │ └── Contents.json
│ │ │ ├── Extra Large.imageset
│ │ │ └── Contents.json
│ │ │ ├── Utilitarian.imageset
│ │ │ └── Contents.json
│ │ │ ├── Graphic Extra Large.imageset
│ │ │ └── Contents.json
│ │ │ └── Contents.json
│ └── Info.plist
├── watchOS Example
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ └── Interface.storyboard
│ └── Info.plist
└── NativeUIKit.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── ivanvorobei.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
│ ├── xcuserdata
│ └── ivanvorobei.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── xcshareddata
│ └── xcschemes
│ ├── iOS Example.xcscheme
│ └── watchOS Example.xcscheme
├── .gitignore
├── TODO.md
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ ├── question.md
│ └── bug_report.md
└── PULL_REQUEST_TEMPLATE.md
├── CONTRIBUTING.md
├── LICENSE
├── Package.swift
├── Sources
└── NativeUIKit
│ ├── NativeAppearance.swift
│ ├── Bars
│ ├── NativeMimicrateNavigationBarView.swift
│ ├── ToolBar
│ │ ├── NativeMimicrateNavigationToolBarView.swift
│ │ ├── NativeSmallActionToolBarView.swift
│ │ ├── LargeAction
│ │ │ ├── NativeSkipableLargeActionToolBarView.swift
│ │ │ ├── NativeLargeSmallActionToolBarView.swift
│ │ │ └── NativeLargeActionToolBarView.swift
│ │ └── NativeAppleAuthToolBarView.swift
│ ├── NativeMimicrateBarView.swift
│ └── NativeBorderedView.swift
│ ├── Table
│ ├── LargeHeader
│ │ ├── NativeLargeHeaderViewExtension.swift
│ │ ├── NativeLargeHeaderItem.swift
│ │ └── CellProvider+LargeHeader.swift
│ ├── Empty
│ │ ├── NativeEmptyRowItem.swift
│ │ ├── CellProvider+Empty.swift
│ │ └── NativeEmptyTableViewCell.swift
│ └── Button
│ │ ├── NativeLeftButtonTableViewCell.swift
│ │ ├── CellProvider+Button.swift
│ │ └── NativeDiffableLeftButton.swift
│ ├── Controllers
│ ├── Complex
│ │ ├── Profile
│ │ │ ├── NativeProfileController.swift
│ │ │ ├── NativeAvatarHeaderView.swift
│ │ │ └── NativeProfileHeaderView.swift
│ │ └── Onboarding
│ │ │ ├── Actinos
│ │ │ ├── NativeOnboardingActionsController.swift
│ │ │ └── NativeOnbiardingActionButton.swift
│ │ │ ├── NativeOnboardingController.swift
│ │ │ └── Features
│ │ │ ├── NativeOnboardingFeaturesController.swift
│ │ │ └── NativeOnboardingFeatureView.swift
│ ├── Scroll
│ │ ├── NativeHeaderController.swift
│ │ ├── NativeHeaderTextFieldController.swift
│ │ └── NativeHeaderFullWidthImageController.swift
│ ├── Table
│ │ └── Header
│ │ │ ├── NativeHeaderTableController+HeaderContainerView.swift
│ │ │ └── NativeHeaderTableController.swift
│ └── Navigation
│ │ └── NativeNavigationController.swift
│ ├── Collection
│ ├── LargeHeader
│ │ ├── SPDiffableCollectionHeaderFooterProvider+LargeHeader.swift
│ │ └── NativeLargeHeaderCollectionView.swift
│ └── NativePromoCollectionViewCell.swift
│ ├── Controls
│ ├── NativePlayPauseCompactButton.swift
│ ├── NativeLargeTextField.swift
│ └── Buttons
│ │ ├── NativeSmallActionButton.swift
│ │ ├── NativeMediumActionButton.swift
│ │ └── NativeLargeActionButton.swift
│ ├── NativeLayout.swift
│ ├── Labels
│ ├── NativeFooterView.swift
│ └── NativeModalHeaderView.swift
│ └── Views
│ ├── NativeLargeHeaderView.swift
│ ├── NativePromoView.swift
│ └── NativePlaceholderView.swift
└── CODE_OF_CONDUCT.md
/Assets/Readme/spm-install-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparrowcode/UIKitExtension/HEAD/Assets/Readme/spm-install-preview.png
--------------------------------------------------------------------------------
/Example App/tvOS Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SparrowKit
3 |
4 | @main
5 | class AppDelegate: SPAppWindowDelegate {}
6 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # osX files
2 | .DS_Store
3 | .Trashes
4 |
5 | # Swift Package Manager
6 | .swiftpm
7 |
8 | # Assets
9 | Elements.sketch
10 |
--------------------------------------------------------------------------------
/Example App/iOS Example/App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | import WatchKit
2 |
3 | class ExtensionDelegate: NSObject, WKExtensionDelegate {}
4 |
--------------------------------------------------------------------------------
/Example App/watchOS Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | Here provided ideas or features which will be implemented soon.
4 |
5 | - Readme.
6 | - Example app.
7 | - Add to list in opensource.
8 | - Add docs.
9 | - Added examples of controllers.
10 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example App/watchOS Example/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 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/xcuserdata/ivanvorobei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ivanvorobei
7 |
8 | ---
9 |
10 | **Feature Description**
11 | Describe what functionality you want to see.
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Something is not clear with the project
4 | title: ''
5 | labels: question
6 | assignees: ivanvorobei
7 |
8 | ---
9 |
10 | **Describe the Problem**
11 | A clear and concise description of what you want to do.
12 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/project.xcworkspace/xcuserdata/ivanvorobei.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sparrowcode/UIKitExtension/HEAD/Example App/NativeUIKit.xcodeproj/project.xcworkspace/xcuserdata/ivanvorobei.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Goal
2 |
3 |
4 | ## Checklist
5 |
6 | - [] Testing in compability platforms
7 | - [] Installed correct via `Swift Package Manager` and `Cocoapods`
8 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ivanvorobei
7 | ---
8 |
9 | **Details**
10 | - iOS Version [e.g. 15.2]
11 | - Framework Version [e.g. 1.0.2]
12 | - Installed via [e.g. SPM, Cocoapods, Manually]
13 |
14 | **Describe the Bug**
15 | A clear and concise description of what the bug is.
16 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "layers" : [
7 | {
8 | "filename" : "Front.imagestacklayer"
9 | },
10 | {
11 | "filename" : "Middle.imagestacklayer"
12 | },
13 | {
14 | "filename" : "Back.imagestacklayer"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "layers" : [
7 | {
8 | "filename" : "Front.imagestacklayer"
9 | },
10 | {
11 | "filename" : "Middle.imagestacklayer"
12 | },
13 | {
14 | "filename" : "Back.imagestacklayer"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : ">161"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">183"
12 | }
13 | ],
14 | "info" : {
15 | "author" : "xcode",
16 | "version" : 1
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : ">161"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">183"
12 | }
13 | ],
14 | "info" : {
15 | "author" : "xcode",
16 | "version" : 1
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : ">161"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">183"
12 | }
13 | ],
14 | "info" : {
15 | "author" : "xcode",
16 | "version" : 1
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : ">161"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">183"
12 | }
13 | ],
14 | "info" : {
15 | "author" : "xcode",
16 | "version" : 1
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "tv-marketing",
13 | "scale" : "1x"
14 | },
15 | {
16 | "idiom" : "tv-marketing",
17 | "scale" : "2x"
18 | }
19 | ],
20 | "info" : {
21 | "author" : "xcode",
22 | "version" : 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "tv-marketing",
13 | "scale" : "1x"
14 | },
15 | {
16 | "idiom" : "tv-marketing",
17 | "scale" : "2x"
18 | }
19 | ],
20 | "info" : {
21 | "author" : "xcode",
22 | "version" : 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Here provided more info about project, contribution process and recomended changes.
4 | Please, read it before pull request or create issue.
5 |
6 | ## Codestyle
7 |
8 | ### Marks
9 |
10 | For clean struct code good is using marks.
11 |
12 | ```swift
13 | class Example {
14 |
15 | // MARK: - Init
16 |
17 | init() {}
18 | }
19 | ```
20 |
21 | Here you find all which using in project:
22 |
23 | - // MARK: - Init
24 | - // MARK: - Lifecycle
25 | - // MARK: - Layout
26 | - // MARK: - Public
27 | - // MARK: - Private
28 | - // MARK: - Internal
29 | - // MARK: - Models
30 | - // MARK: - Ovveride
31 |
32 | If you can't find valid, add new to codestyle agreements please. Other can be use if class is large and need struct it even without adding to codestyle agreements.
33 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "filename" : "App Icon - App Store.imagestack",
5 | "idiom" : "tv",
6 | "role" : "primary-app-icon",
7 | "size" : "1280x768"
8 | },
9 | {
10 | "filename" : "App Icon.imagestack",
11 | "idiom" : "tv",
12 | "role" : "primary-app-icon",
13 | "size" : "400x240"
14 | },
15 | {
16 | "filename" : "Top Shelf Image Wide.imageset",
17 | "idiom" : "tv",
18 | "role" : "top-shelf-image-wide",
19 | "size" : "2320x720"
20 | },
21 | {
22 | "filename" : "Top Shelf Image.imageset",
23 | "idiom" : "tv",
24 | "role" : "top-shelf-image",
25 | "size" : "1920x720"
26 | }
27 | ],
28 | "info" : {
29 | "author" : "xcode",
30 | "version" : 1
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Example App/watchOS Example/Base.lproj/Interface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/xcuserdata/ivanvorobei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | iOS Example.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | tvOS Example.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 3
16 |
17 | watchOS Example.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 2
21 |
22 |
23 | SuppressBuildableAutocreation
24 |
25 | F4C33DD826C92DF8001A28B1
26 |
27 | primary
28 |
29 |
30 | F4C33E2F26C932C8001A28B1
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "SparrowKit",
6 | "repositoryURL": "https://github.com/ivanvorobei/SparrowKit",
7 | "state": {
8 | "branch": null,
9 | "revision": "4a6283d0e5e010a99c038bd103a8c883245aafa5",
10 | "version": "3.5.4"
11 | }
12 | },
13 | {
14 | "package": "SPDiffable",
15 | "repositoryURL": "https://github.com/ivanvorobei/SPDiffable",
16 | "state": {
17 | "branch": null,
18 | "revision": "49d6a86438d0e82efc8da1e0202bceee9b1f5666",
19 | "version": "4.0.6"
20 | }
21 | },
22 | {
23 | "package": "SPPerspective",
24 | "repositoryURL": "https://github.com/ivanvorobei/SPPerspective",
25 | "state": {
26 | "branch": null,
27 | "revision": "580ed06a5daec94c5095379971570289b429fa3d",
28 | "version": "1.4.1"
29 | }
30 | }
31 | ]
32 | },
33 | "version": 1
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ivan Vorobei
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.
22 |
--------------------------------------------------------------------------------
/Example App/watchOS Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | UISupportedInterfaceOrientations
22 |
23 | UIInterfaceOrientationPortrait
24 | UIInterfaceOrientationPortraitUpsideDown
25 |
26 | WKCompanionAppBundleIdentifier
27 | by.ivanvorobei.opensource.nativeuikit.ios
28 | WKWatchKitApp
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | arm64
30 |
31 | UIUserInterfaceStyle
32 | Automatic
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | CLKComplicationPrincipalClass
22 | $(PRODUCT_MODULE_NAME).ComplicationController
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | WKAppBundleIdentifier
28 | by.ivanvorobei.opensource.nativeuikit.ios.watchkitapp
29 |
30 | NSExtensionPointIdentifier
31 | com.apple.watchkit
32 |
33 | WKExtensionDelegateClassName
34 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Example App/iOS Example/Scenes/RootController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | import UIKit
23 | import SparrowKit
24 | import NativeUIKit
25 |
26 | class RootController: UIViewController {
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "NativeUIKit",
7 | platforms: [
8 | .iOS(.v12),
9 | .tvOS(.v12),
10 | .watchOS(.v6)
11 | ],
12 | products: [
13 | .library(
14 | name: "NativeUIKit", targets: ["NativeUIKit"]
15 | )
16 | ],
17 | dependencies: [
18 | .package(url: "https://github.com/ivanvorobei/SparrowKit", .upToNextMajor(from: "3.6.0")),
19 | .package(url: "https://github.com/ivanvorobei/SPPerspective", .upToNextMajor(from: "1.4.1")),
20 | .package(url: "https://github.com/ivanvorobei/SPDiffable", .upToNextMajor(from: "4.1.0")),
21 | .package(url: "https://github.com/ivanvorobei/SPPageController", .upToNextMajor(from: "1.3.2"))
22 | ],
23 | targets: [
24 | .target(
25 | name: "NativeUIKit",
26 | dependencies: [
27 | .product(name: "SparrowKit", package: "SparrowKit"),
28 | .product(name: "SPPerspective", package: "SPPerspective"),
29 | .product(name: "SPDiffable", package: "SPDiffable"),
30 | .product(name: "SPPageController", package: "SPPageController")
31 | ],
32 | swiftSettings: [
33 | .define("NATIVEUIKIT_SPM")
34 | ]
35 | )
36 | ],
37 | swiftLanguageVersions: [.v5]
38 | )
39 |
--------------------------------------------------------------------------------
/Example App/watchOS Example Extension/Assets.xcassets/Complication.complicationset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "filename" : "Circular.imageset",
5 | "idiom" : "watch",
6 | "role" : "circular"
7 | },
8 | {
9 | "filename" : "Extra Large.imageset",
10 | "idiom" : "watch",
11 | "role" : "extra-large"
12 | },
13 | {
14 | "filename" : "Graphic Bezel.imageset",
15 | "idiom" : "watch",
16 | "role" : "graphic-bezel"
17 | },
18 | {
19 | "filename" : "Graphic Circular.imageset",
20 | "idiom" : "watch",
21 | "role" : "graphic-circular"
22 | },
23 | {
24 | "filename" : "Graphic Corner.imageset",
25 | "idiom" : "watch",
26 | "role" : "graphic-corner"
27 | },
28 | {
29 | "filename" : "Graphic Extra Large.imageset",
30 | "idiom" : "watch",
31 | "role" : "graphic-extra-large"
32 | },
33 | {
34 | "filename" : "Graphic Large Rectangular.imageset",
35 | "idiom" : "watch",
36 | "role" : "graphic-large-rectangular"
37 | },
38 | {
39 | "filename" : "Modular.imageset",
40 | "idiom" : "watch",
41 | "role" : "modular"
42 | },
43 | {
44 | "filename" : "Utilitarian.imageset",
45 | "idiom" : "watch",
46 | "role" : "utilitarian"
47 | }
48 | ],
49 | "info" : {
50 | "author" : "xcode",
51 | "version" : 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/NativeAppearance.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 |
25 | enum NativeAppearance {
26 |
27 | enum Corners {
28 |
29 | static var readable_area: CGFloat { 15 }
30 | }
31 |
32 | static var actionable_element_highlight_opacity: CGFloat { 0.6 }
33 | }
34 | #endif
35 |
--------------------------------------------------------------------------------
/Assets/Readme/Elements/NativePlayPauseCompactButton.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Example App/iOS Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Assets/Readme/Elements/NativeSmallActionButton.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/NativeMimicrateNavigationBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeMimicrateNavigationBarView: NativeMimicrateBarView {
27 |
28 | // MARK: - Init
29 |
30 | public init() {
31 | super.init(borderPosition: .bottom)
32 | }
33 |
34 | public required init?(coder aDecoder: NSCoder) {
35 | fatalError("init(coder:) has not been implemented")
36 | }
37 | }
38 | #endif
39 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/LargeHeader/NativeLargeHeaderViewExtension.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 |
25 | extension NativeLargeHeaderView {
26 |
27 | func configure(with item: NativeLargeHeaderItem, section: Int) {
28 | titleLabel.text = item.title
29 | if let actionTitle = item.actionTitle {
30 | button.setTitle(actionTitle)
31 | diffableButtonAction = {
32 | item.action?(item, .init(row: .zero, section: section))
33 | }
34 | }
35 | }
36 | }
37 | #endif
38 |
--------------------------------------------------------------------------------
/Example App/iOS Example/App/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Empty/NativeEmptyRowItem.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | @available(iOS 13.0, *)
28 | open class NativeEmptyRowItem: SPDiffableTableRow {
29 |
30 | var verticalMargins: NativeEmptyTableViewCell.Margins
31 |
32 | public init(id: String, verticalMargins: NativeEmptyTableViewCell.Margins, text: String, detail: String?) {
33 | self.verticalMargins = verticalMargins
34 | super.init(id: id, text: text, detail: detail)
35 | }
36 | }
37 | #endif
38 |
--------------------------------------------------------------------------------
/Example App/iOS Example/App/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | import UIKit
23 | import SparrowKit
24 | import NativeUIKit
25 |
26 | @UIApplicationMain
27 | class AppDelegate: SPAppWindowDelegate {
28 |
29 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
30 | let rootController = RootController()
31 | let navigationController = NativeNavigationController(rootViewController: rootController)
32 | makeKeyAndVisible(viewController: navigationController, tint: .systemBlue)
33 | return true
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/Example App/tvOS Example/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/LargeHeader/NativeLargeHeaderItem.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2020 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS) || os(tvOS))
23 | import UIKit
24 | import SPDiffable
25 |
26 | /**
27 | SPDiffable: Native large header with button.
28 | */
29 | open class NativeLargeHeaderItem: SPDiffableItem, SPDiffableItemActionable {
30 |
31 | open var title: String
32 | open var actionTitle: String?
33 | open var action: Action?
34 |
35 | public init(id: String? = nil, title: String, actionTitle: String? = nil, action: Action? = nil) {
36 | self.title = title
37 | self.actionTitle = actionTitle
38 | self.action = action
39 | super.init(id: id ?? title)
40 | }
41 | }
42 | #endif
43 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/LargeHeader/CellProvider+LargeHeader.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SPDiffable
25 |
26 | @available(iOS 13.0, *)
27 | extension SPDiffableTableDataSource.HeaderFooterProvider {
28 |
29 | public static var largeHeader: SPDiffableTableDataSource.HeaderFooterProvider {
30 | return SPDiffableTableDataSource.HeaderFooterProvider() { (tableView, section, item) -> UIView? in
31 | guard let header = item as? NativeLargeHeaderItem else { return nil }
32 | let view = NativeLargeHeaderView()
33 | view.configure(with: header, section: section)
34 | return view
35 | }
36 | }
37 | }
38 | #endif
39 |
--------------------------------------------------------------------------------
/Example App/watchOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "role" : "notificationCenter",
6 | "scale" : "2x",
7 | "size" : "24x24",
8 | "subtype" : "38mm"
9 | },
10 | {
11 | "idiom" : "watch",
12 | "role" : "notificationCenter",
13 | "scale" : "2x",
14 | "size" : "27.5x27.5",
15 | "subtype" : "42mm"
16 | },
17 | {
18 | "idiom" : "watch",
19 | "role" : "companionSettings",
20 | "scale" : "2x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "watch",
25 | "role" : "companionSettings",
26 | "scale" : "3x",
27 | "size" : "29x29"
28 | },
29 | {
30 | "idiom" : "watch",
31 | "role" : "appLauncher",
32 | "scale" : "2x",
33 | "size" : "40x40",
34 | "subtype" : "38mm"
35 | },
36 | {
37 | "idiom" : "watch",
38 | "role" : "appLauncher",
39 | "scale" : "2x",
40 | "size" : "44x44",
41 | "subtype" : "40mm"
42 | },
43 | {
44 | "idiom" : "watch",
45 | "role" : "appLauncher",
46 | "scale" : "2x",
47 | "size" : "50x50",
48 | "subtype" : "44mm"
49 | },
50 | {
51 | "idiom" : "watch",
52 | "role" : "quickLook",
53 | "scale" : "2x",
54 | "size" : "86x86",
55 | "subtype" : "38mm"
56 | },
57 | {
58 | "idiom" : "watch",
59 | "role" : "quickLook",
60 | "scale" : "2x",
61 | "size" : "98x98",
62 | "subtype" : "42mm"
63 | },
64 | {
65 | "idiom" : "watch",
66 | "role" : "quickLook",
67 | "scale" : "2x",
68 | "size" : "108x108",
69 | "subtype" : "44mm"
70 | },
71 | {
72 | "idiom" : "watch-marketing",
73 | "scale" : "1x",
74 | "size" : "1024x1024"
75 | }
76 | ],
77 | "info" : {
78 | "author" : "xcode",
79 | "version" : 1
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Example App/iOS Example/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Profile/NativeProfileController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | @available(iOS 13.0, *)
28 | open class NativeProfileController: NativeHeaderTableController {
29 |
30 | // MARK: - Views
31 |
32 | public let headerView = NativeAvatarHeaderView()
33 |
34 | // MARK: - Init
35 |
36 | public init(style: UITableView.Style = .insetGrouped) {
37 | super.init(style: style, headerView: headerView)
38 | }
39 |
40 | public required init?(coder: NSCoder) {
41 | fatalError("init(coder:) has not been implemented")
42 | }
43 |
44 | // MARK: - Lifecycle
45 |
46 | open override func viewDidLoad() {
47 | super.viewDidLoad()
48 | navigationItem.title = .empty
49 | }
50 | }
51 | #endif
52 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Empty/CellProvider+Empty.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SPDiffable
25 |
26 | @available(iOS 13.0, *)
27 | extension SPDiffableTableDataSource.CellProvider {
28 |
29 | public static var empty: SPDiffableTableDataSource.CellProvider {
30 | return SPDiffableTableDataSource.CellProvider() { (tableView, indexPath, item) -> UITableViewCell? in
31 | guard let item = item as? NativeEmptyRowItem else { return nil }
32 | let cell = tableView.dequeueReusableCell(withClass: NativeEmptyTableViewCell.self, for: indexPath)
33 | cell.placeholderView.headerLabel.text = item.text
34 | cell.placeholderView.descriptionLabel.text = item.detail
35 | cell.verticalMargins = item.verticalMargins
36 | return cell
37 | }
38 | }
39 | }
40 | #endif
41 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Collection/LargeHeader/SPDiffableCollectionHeaderFooterProvider+LargeHeader.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | import UIKit
23 | import SPDiffable
24 |
25 | @available(iOS 13.0, tvOS 13.0, *)
26 | extension SPDiffableCollectionDataSource.HeaderFooterProvider {
27 |
28 | #if (os(iOS))
29 | public static var largeHeader: SPDiffableCollectionDataSource.HeaderFooterProvider {
30 | return SPDiffableCollectionDataSource.HeaderFooterProvider.init { collectionView, kind, indexPath, item in
31 | guard let header = item as? NativeLargeHeaderItem else { return nil }
32 | let view = collectionView.dequeueReusableSupplementaryView(withCalss: NativeLargeHeaderCollectionView.self, kind: kind, for: indexPath)
33 | view.headerView.configure(with: header, section: indexPath.section)
34 | return view
35 | }
36 | }
37 | #endif
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Button/NativeLeftButtonTableViewCell.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeLeftButtonTableViewCell: SPTableViewCell {
27 |
28 | public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
29 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
30 | }
31 |
32 | required public init?(coder aDecoder: NSCoder) {
33 | fatalError("init(coder:) has not been implemented")
34 | }
35 |
36 | open override func commonInit() {
37 | super.commonInit()
38 | textLabel?.font = .preferredFont(forTextStyle: .body, weight: .medium)
39 | higlightStyle = .content
40 | }
41 |
42 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
43 | let superSize = super.sizeThatFits(size)
44 | return .init(width: superSize.width, height: superSize.height + 6)
45 | }
46 | }
47 | #endif
48 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Button/CellProvider+Button.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SPDiffable
25 |
26 | @available(iOS 13.0, *)
27 | extension SPDiffableTableDataSource.CellProvider {
28 |
29 | public static var button: SPDiffableTableDataSource.CellProvider {
30 | return SPDiffableTableDataSource.CellProvider() { (tableView, indexPath, item) -> UITableViewCell? in
31 | guard let item = item as? NativeDiffableLeftButton else { return nil }
32 | let cell = tableView.dequeueReusableCell(withClass: NativeLeftButtonTableViewCell.self, for: indexPath)
33 | cell.textLabel?.text = item.text
34 | cell.textLabel?.textColor = item.textColor
35 | cell.detailTextLabel?.text = item.detail
36 | cell.detailTextLabel?.textColor = item.detailColor
37 | cell.imageView?.image = item.icon
38 | cell.accessoryType = item.accessoryType
39 | cell.higlightStyle = item.higlightStyle
40 | return cell
41 | }
42 | }
43 | }
44 | #endif
45 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/NativeMimicrateNavigationToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeMimicrateToolBarView: NativeMimicrateBarView {
27 |
28 | // MARK: - Init
29 |
30 | public init() {
31 | super.init(borderPosition: .top)
32 | }
33 |
34 | public required init?(coder aDecoder: NSCoder) {
35 | fatalError("init(coder:) has not been implemented")
36 | }
37 |
38 | open override func commonInit() {
39 | super.commonInit()
40 | insetsLayoutMarginsFromSafeArea = false
41 | layoutMargins.top = 16
42 | }
43 |
44 | // MARK: - Layout
45 |
46 | open override func layoutSubviews() {
47 | super.layoutSubviews()
48 | guard let superview = superview else { return }
49 | let contentWidth = min(440, superview.readableWidth)
50 | let horizontalMargin = (frame.width - contentWidth) / 2
51 | layoutMargins.left = horizontalMargin
52 | layoutMargins.right = horizontalMargin
53 | }
54 | }
55 | #endif
56 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/NativeSmallActionToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeSmallActionToolBarView: NativeMimicrateToolBarView {
27 |
28 | public let actionButton = SPDimmedButton().do {
29 | $0.applyDefaultAppearance(with: .tintedContent)
30 | $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .title3, weight: .semibold)
31 | }
32 |
33 | // MARK: - Init
34 |
35 | open override func commonInit() {
36 | super.commonInit()
37 | addSubview(actionButton)
38 | }
39 |
40 | // MARK: - Layout
41 |
42 | open override func layoutSubviews() {
43 | super.layoutSubviews()
44 | actionButton.setWidthAndFit(width: layoutWidth)
45 | actionButton.frame.origin.y = layoutMargins.top + 16
46 | actionButton.setXCenter()
47 | }
48 |
49 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
50 | layoutSubviews()
51 | return .init(width: size.width, height: actionButton.frame.maxY + layoutMargins.bottom)
52 | }
53 | }
54 | #endif
55 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Collection/NativePromoCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPPerspective
26 |
27 | open class NativePromoCollectionViewCell: SPCollectionViewCell {
28 |
29 | // MARK: - Views
30 |
31 | public let promoView = NativePromoView()
32 |
33 | // MARK: - Init
34 |
35 | open override func commonInit() {
36 | super.commonInit()
37 | contentView.layoutMargins = .zero
38 | contentView.addSubview(promoView)
39 | }
40 |
41 | open override func prepareForReuse() {
42 | super.prepareForReuse()
43 | promoView.iconView.resetPerspective()
44 | }
45 |
46 | // MARK: - Layout
47 |
48 | open override func layoutSubviews() {
49 | super.layoutSubviews()
50 | promoView.layout(y: contentView.layoutMargins.top)
51 | }
52 |
53 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
54 | let superSize = super.sizeThatFits(size)
55 | layoutSubviews()
56 | return .init(width: superSize.width, height: promoView.frame.maxY + contentView.layoutMargins.bottom)
57 | }
58 | }
59 | #endif
60 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Button/NativeDiffableLeftButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | @available(iOS 13.0, *)
28 | open class NativeDiffableLeftButton: SPDiffableTableRow {
29 |
30 | open var textColor: UIColor
31 | open var detailColor: UIColor
32 | open var higlightStyle: SPTableViewCell.HiglightStyle
33 |
34 | public init(
35 | id: String? = nil,
36 | text: String,
37 | textColor: UIColor = .label,
38 | detail: String? = nil,
39 | detailColor: UIColor = .secondaryLabel,
40 | icon: UIImage? = nil,
41 | accessoryType: UITableViewCell.AccessoryType = .none,
42 | higlightStyle: SPTableViewCell.HiglightStyle = .content,
43 | action: SPDiffableTableRow.Action? = nil
44 | ) {
45 | self.textColor = textColor
46 | self.detailColor = detailColor
47 | self.higlightStyle = higlightStyle
48 |
49 | super.init(
50 | id: id,
51 | text: text,
52 | detail: detail,
53 | icon: icon,
54 | accessoryType: accessoryType,
55 | action: action
56 | )
57 | }
58 | }
59 | #endif
60 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Scroll/NativeHeaderController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeHeaderController: SPScrollController {
27 |
28 | // MARK: - Views
29 |
30 | public let headerView: NativeModalHeaderView
31 |
32 | // MARK: - Init
33 |
34 | public init(image: UIImage?, title: String, subtitle: String) {
35 | self.headerView = NativeModalHeaderView(image: image, title: title, subtitle: subtitle)
36 | super.init()
37 | }
38 |
39 | public required init?(coder: NSCoder) {
40 | fatalError("init(coder:) has not been implemented")
41 | }
42 |
43 | // MARK: - Lifecycle
44 |
45 | open override func viewDidLoad() {
46 | super.viewDidLoad()
47 | scrollView.contentInset.bottom = NativeLayout.Spaces.Scroll.bottom_inset_reach_end
48 | scrollView.addSubview(headerView)
49 | }
50 |
51 | open override func viewDidLayoutSubviews() {
52 | super.viewDidLayoutSubviews()
53 | headerView.layout(y: NativeLayout.Spaces.default)
54 | scrollView.contentSize = .init(width: view.frame.width, height: headerView.frame.maxY)
55 | }
56 | }
57 | #endif
58 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controls/NativePlayPauseCompactButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | @available(iOS 13, *)
27 | open class NativePlayPauseCompactButton: SPDimmedButton {
28 |
29 | // MARK: - Data
30 |
31 | open var appearance: Appearance = .play {
32 | didSet {
33 | updateAppearance()
34 | }
35 | }
36 | open var playImage = UIImage.system("play.fill", font: .preferredFont(forTextStyle: .body))
37 | open var pauseImage = UIImage.system("pause.fill", font: .preferredFont(forTextStyle: .body))
38 |
39 | // MARK: - Init
40 |
41 | open override func commonInit() {
42 | super.commonInit()
43 | contentEdgeInsets = .init(side: 8)
44 | applyDefaultAppearance(with: .tintedContent)
45 | updateAppearance()
46 | }
47 |
48 | // MARK: - Internal
49 |
50 | internal func updateAppearance() {
51 | switch self.appearance {
52 | case .play:
53 | setImage(playImage)
54 | case .pause:
55 | setImage(pauseImage)
56 | }
57 | }
58 |
59 | // MARK: - Models
60 |
61 | public enum Appearance {
62 |
63 | case play
64 | case pause
65 | }
66 | }
67 | #endif
68 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Collection/LargeHeader/NativeLargeHeaderCollectionView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeLargeHeaderCollectionView: SPCollectionReusableView {
27 |
28 | public let headerView = NativeLargeHeaderView()
29 |
30 | open override func commonInit() {
31 | super.commonInit()
32 | insetsLayoutMarginsFromSafeArea = false
33 | layoutMargins = .zero
34 | addSubview(headerView)
35 | }
36 |
37 | open override func layoutSubviews() {
38 | super.layoutSubviews()
39 | headerView.layout(y: layoutMargins.top)
40 | }
41 |
42 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
43 | let superSize = super.sizeThatFits(size)
44 | return .init(width: superSize.width, height: headerView.frame.height + layoutMargins.bottom)
45 | }
46 |
47 | static public func size(for item: NativeLargeHeaderItem, in collectionView: UICollectionView) -> CGSize {
48 | let view = NativeLargeHeaderView()
49 | view.configure(with: item, section: .zero)
50 | view.setWidthAndFit(width: collectionView.layoutWidth)
51 | return .init(width: collectionView.frame.width, height: view.frame.height)
52 | }
53 | }
54 | #endif
55 |
--------------------------------------------------------------------------------
/Assets/Readme/Elements/NativeAvatarView.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Scroll/NativeHeaderTextFieldController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeHeaderTextFieldController: NativeHeaderController {
27 |
28 | // MARK: - Views
29 |
30 | public let textField = NativeLargeTextField().do {
31 | $0.returnKeyType = .done
32 | $0.autocapitalizationType = .words
33 | }
34 |
35 | public let footerView = NativeFooterView()
36 |
37 | // MARK: - Lifecycle
38 |
39 | open override func viewDidLoad() {
40 | super.viewDidLoad()
41 | if #available(iOS 13.0, *) {
42 | view.backgroundColor = .systemBackground
43 | }
44 | scrollView.addSubviews(textField, footerView)
45 | dismissKeyboardWhenTappedAround()
46 | }
47 |
48 | // MARK: - Layout
49 |
50 | open override func viewDidLayoutSubviews() {
51 | super.viewDidLayoutSubviews()
52 | textField.layout(y: headerView.frame.maxY + NativeLayout.Spaces.default + NativeLayout.Spaces.default_half)
53 | footerView.setWidthAndFit(width: textField.frame.width)
54 | footerView.frame.origin.x = textField.frame.origin.x
55 | footerView.frame.origin.y = textField.frame.maxY
56 | scrollView.contentSize = .init(width: view.frame.width, height: footerView.frame.maxY)
57 | }
58 | }
59 | #endif
60 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/NativeLayout.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 |
25 | public enum NativeLayout {
26 |
27 | public enum Sizes {
28 |
29 | public static var actionable_area_maximum_width: CGFloat { 408 }
30 | public static var not_actionable_area_maximum_width: CGFloat { 382 }
31 | }
32 |
33 | public enum Spaces {
34 |
35 | public static var step: CGFloat = 4
36 |
37 | public static var default_less: CGFloat { step * 3 }
38 | public static var `default`: CGFloat { step * 4 }
39 | public static var default_more: CGFloat { step * 5 }
40 |
41 | public static var default_half: CGFloat { self.default / 2 }
42 | public static var default_double: CGFloat { self.default * 2 }
43 |
44 | public enum Margins {
45 |
46 | public static var full_screen_horizontal: CGFloat { Spaces.default }
47 | public static var modal_screen_horizontal: CGFloat { step * 5 }
48 | }
49 |
50 | public enum Scroll {
51 |
52 | public static var top_inset_transparent_navigation: CGFloat { step * 2 }
53 | public static var bottom_inset_reach_end: CGFloat { step * 9 }
54 | public static var bottom_inset_when_keyboard_can_appear: CGFloat { step * 8 }
55 | }
56 | }
57 | }
58 | #endif
59 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/LargeAction/NativeSkipableLargeActionToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeSkipableLargeActionToolBarView: NativeLargeActionToolBarView {
27 |
28 | // MARK: - Views
29 |
30 | public let skipButton = SPDimmedButton().do {
31 | $0.applyDefaultAppearance(with: .init(content: .systemGray, background: .clear))
32 | $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body, weight: .semibold)
33 | }
34 |
35 | // MARK: - Init
36 |
37 | open override func commonInit() {
38 | super.commonInit()
39 | addSubview(skipButton)
40 | }
41 |
42 | // MARK: - Actions
43 |
44 | open override func setLoading(_ state: Bool) {
45 | super.setLoading(state)
46 | skipButton.isHidden = state
47 | }
48 |
49 | // MARK: - Layout
50 |
51 | open override func layoutSubviews() {
52 | super.layoutSubviews()
53 | skipButton.setWidthAndFit(width: layoutWidth)
54 | skipButton.frame.origin.y = actionButton.frame.maxY + 12
55 | skipButton.setXCenter()
56 | }
57 |
58 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
59 | layoutSubviews()
60 | return .init(width: size.width, height: skipButton.frame.maxY + layoutMargins.bottom)
61 | }
62 | }
63 | #endif
64 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/LargeAction/NativeLargeSmallActionToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeLargeSmallActionToolBarView: NativeLargeActionToolBarView {
27 |
28 | // MARK: - Views
29 |
30 | public let secondActionButton = SPDimmedButton().do {
31 | $0.applyDefaultAppearance(with: .tintedContent)
32 | $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline, addPoints: -1)
33 | }
34 |
35 | // MARK: - Init
36 |
37 | open override func commonInit() {
38 | super.commonInit()
39 | addSubview(secondActionButton)
40 | }
41 |
42 | // MARK: - Actions
43 |
44 | open override func setLoading(_ state: Bool) {
45 | super.setLoading(state)
46 | secondActionButton.isHidden = state
47 | }
48 |
49 | // MARK: - Layout
50 |
51 | open override func layoutSubviews() {
52 | super.layoutSubviews()
53 | secondActionButton.setWidthAndFit(width: layoutWidth)
54 | secondActionButton.frame.origin.y = actionButton.frame.maxY + 12
55 | secondActionButton.setXCenter()
56 | }
57 |
58 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
59 | layoutSubviews()
60 | return .init(width: size.width, height: secondActionButton.frame.maxY + layoutMargins.bottom)
61 | }
62 | }
63 | #endif
64 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Scroll/NativeHeaderFullWidthImageController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | @available(iOS 13.0, *)
27 | open class NativeHeaderFullWidthImageController: SPScrollController {
28 |
29 | // MARK: - Views
30 |
31 | public let headerImageView = SPImageView().do {
32 | $0.backgroundColor = .systemGray.alpha(0.1)
33 | $0.contentMode = .scaleAspectFill
34 | }
35 |
36 | public let titlesView = NativeModalHeaderView()
37 |
38 | // MARK: - Lifecycle
39 |
40 | open override func viewDidLoad() {
41 | super.viewDidLoad()
42 | view.backgroundColor = .secondarySystemBackground
43 | scrollView.showsVerticalScrollIndicator = false
44 | scrollView.addSubviews([headerImageView, titlesView])
45 | navigationController?.navigationBar.setAppearance(.transparentAlways)
46 | }
47 |
48 | // MARK: - Layout
49 |
50 | open override func viewDidLayoutSubviews() {
51 | super.viewDidLayoutSubviews()
52 | headerImageView.frame = .init(x: .zero, y: -scrollView.layoutMargins.top, width: view.frame.width, height: view.frame.height * 0.45)
53 | titlesView.layout(y: headerImageView.frame.maxY + NativeLayout.Spaces.default_double)
54 | scrollView.contentSize = .init(
55 | width: view.frame.width,
56 | height: titlesView.frame.maxY + NativeLayout.Spaces.default_double
57 | )
58 | }
59 | }
60 | #endif
61 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Labels/NativeFooterView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeFooterView: SPView {
27 |
28 | // MARK: - Views
29 |
30 | public let label = SPLabel().do {
31 | $0.font = .preferredFont(forTextStyle: .footnote, addPoints: 1)
32 | $0.numberOfLines = .zero
33 | if #available(iOS 13.0, *) {
34 | $0.textColor = .secondaryLabel
35 | } else {
36 | $0.textColor = .gray
37 | }
38 | }
39 |
40 | public override init() {
41 | super.init()
42 | }
43 |
44 | public init(text: String) {
45 | super.init()
46 | label.text = text
47 | }
48 |
49 | required public init?(coder aDecoder: NSCoder) {
50 | fatalError("init(coder:) has not been implemented")
51 | }
52 |
53 | open override func commonInit() {
54 | super.commonInit()
55 | layoutMargins = .init(top: NativeLayout.Spaces.default_half, left: 16, bottom: NativeLayout.Spaces.default_half, right: .zero)
56 | addSubview(label)
57 | }
58 |
59 | open override func layoutSubviews() {
60 | super.layoutSubviews()
61 | label.layoutDynamicHeight(x: layoutMargins.left, y: layoutMargins.top, width: layoutWidth)
62 | }
63 |
64 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
65 | layoutSubviews()
66 | return .init(width: size.width, height: label.frame.maxY + layoutMargins.bottom)
67 | }
68 | }
69 | #endif
70 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Table/Header/NativeHeaderTableController+HeaderContainerView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | @available(iOS 13.0, *)
28 | extension NativeHeaderTableController {
29 |
30 | open class HeaderContainerView: SPView {
31 |
32 | // MARK: - Public
33 |
34 | public let contentView: UIView
35 |
36 | // MARK: - Init
37 |
38 | public init(contentView: UIView) {
39 | self.contentView = contentView
40 | super.init()
41 | }
42 |
43 | public required init?(coder aDecoder: NSCoder) {
44 | fatalError("init(coder:) has not been implemented")
45 | }
46 |
47 | public override func commonInit() {
48 | super.commonInit()
49 | insetsLayoutMarginsFromSafeArea = false
50 | contentView.insetsLayoutMarginsFromSafeArea = false
51 | layoutMargins = .zero
52 | addSubview(contentView)
53 | }
54 |
55 | // MARK: - Layout
56 |
57 | public override func layoutSubviews() {
58 | super.layoutSubviews()
59 | contentView.setWidthAndFit(width: layoutWidth)
60 | contentView.frame.origin.x = layoutMargins.left
61 | contentView.frame.origin.y = layoutMargins.top
62 | }
63 |
64 | public override func sizeThatFits(_ size: CGSize) -> CGSize {
65 | frame.setWidth(size.width)
66 | layoutSubviews()
67 | return .init(width: size.width, height: contentView.frame.maxY + layoutMargins.bottom)
68 | }
69 | }
70 | }
71 | #endif
72 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/NativeMimicrateBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: View with mimicrate to navigation and toolbar views.
28 | */
29 | open class NativeMimicrateBarView: SPView {
30 |
31 | // MARK: - Views
32 |
33 | public let borderedView: NativeBorderedView
34 | public let backgroundView: UIVisualEffectView
35 |
36 | // MARK: - Init
37 |
38 | public init(borderPosition: NativeBorderedView.Position) {
39 | self.borderedView = NativeBorderedView(position: borderPosition)
40 | self.backgroundView = UIVisualEffectView.init(style: .regular)
41 | super.init()
42 | }
43 |
44 | public required init?(coder aDecoder: NSCoder) {
45 | fatalError("init(coder:) has not been implemented")
46 | }
47 |
48 | open override func commonInit() {
49 | super.commonInit()
50 | addSubview(backgroundView)
51 | addSubview(borderedView)
52 | setVisible(progress: 1)
53 | }
54 |
55 | // MARK: - Actions
56 |
57 | /**
58 | NativeUIKit: Show or hide bar.
59 |
60 | - parameter progress: Value in range from `0` to `1` to visible or not view.
61 | */
62 | open func setVisible(progress: CGFloat) {
63 | var alpha: CGFloat = progress
64 | if progress < 0 { alpha = 0 }
65 | if progress > 1 { alpha = 1 }
66 | self.borderedView.alpha = alpha
67 | self.backgroundView.alpha = alpha
68 | }
69 |
70 | // MARK: - Layout
71 |
72 | open override func layoutSubviews() {
73 | super.layoutSubviews()
74 | backgroundView.setEqualSuperviewBounds()
75 | borderedView.setEqualSuperviewBounds()
76 | }
77 | }
78 | #endif
79 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Profile/NativeAvatarHeaderView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | @available(iOS 13.0, *)
27 | open class NativeAvatarHeaderView: SPView {
28 |
29 | // MARK: - Public
30 |
31 | public let avatarView = NativeAvatarView().do {
32 | $0.avatarAppearance = .placeholder
33 | $0.isEditable = true
34 | }
35 |
36 | // MARK: - Private
37 |
38 | private var extendView = SPView()
39 |
40 | // MARK: - Init
41 |
42 | open override func commonInit() {
43 | super.commonInit()
44 | backgroundColor = .clear
45 | addSubviews([extendView, avatarView])
46 |
47 | layoutMargins = .init(
48 | top: NativeLayout.Spaces.default,
49 | left: NativeLayout.Spaces.default_double,
50 | bottom: NativeLayout.Spaces.default_more,
51 | right: NativeLayout.Spaces.default_double
52 | )
53 | }
54 |
55 | // MARK: - Ovveride
56 |
57 | open override var backgroundColor: UIColor? {
58 | didSet {
59 | extendView.backgroundColor = backgroundColor
60 | }
61 | }
62 |
63 | // MARK: - Layout
64 |
65 | open override func layoutSubviews() {
66 | super.layoutSubviews()
67 | extendView.frame = .init(x: .zero, maxY: .zero, width: frame.width, height: 1000)
68 |
69 | avatarView.sizeToFit()
70 | avatarView.setXCenter()
71 | avatarView.frame.origin.y = layoutMargins.top
72 | }
73 |
74 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
75 | layoutSubviews()
76 | return .init(width: frame.width, height: avatarView.frame.maxY + layoutMargins.bottom)
77 | }
78 | }
79 | #endif
80 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/NativeAppleAuthToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && canImport(AuthenticationServices) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import AuthenticationServices
26 |
27 | @available(iOS 13.0, *)
28 | open class NativeAppleAuthToolBarView: NativeMimicrateToolBarView {
29 |
30 | // MARK: - Views
31 |
32 | public let authButton = ASAuthorizationAppleIDButton()
33 |
34 | public let footerLabel = SPLabel().do {
35 | $0.font = .preferredFont(forTextStyle: .footnote)
36 | $0.numberOfLines = .zero
37 | $0.textColor = .secondaryLabel
38 | }
39 |
40 | // MARK: - Init
41 |
42 | open override func commonInit() {
43 | super.commonInit()
44 | addSubview(authButton)
45 | addSubview(footerLabel)
46 | }
47 |
48 | // MARK: - Layout
49 |
50 | internal let footerLeftInset: CGFloat = 20
51 |
52 | open override func layoutSubviews() {
53 | super.layoutSubviews()
54 |
55 | let authButtonWidth = min(readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
56 | authButton.frame.setWidth(authButtonWidth)
57 | authButton.frame.setHeight(52)
58 | authButton.setXCenter()
59 | authButton.frame.origin.y = layoutMargins.top
60 |
61 | if footerLabel.text != nil {
62 | footerLabel.layoutDynamicHeight(x: layoutMargins.left + footerLeftInset, y: authButton.frame.maxY + 12, width: layoutWidth - footerLeftInset)
63 | }
64 | }
65 |
66 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
67 | layoutSubviews()
68 | if footerLabel.text == nil {
69 | return .init(width: size.width, height: authButton.frame.maxY + layoutMargins.bottom)
70 | } else {
71 | return .init(width: size.width, height: footerLabel.frame.maxY + layoutMargins.bottom)
72 | }
73 | }
74 | }
75 | #endif
76 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controls/NativeLargeTextField.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeLargeTextField: SPInsetsTextField {
27 |
28 | // MARK: - Init
29 |
30 | open override func commonInit() {
31 | super.commonInit()
32 | if #available(iOS 13.0, *) {
33 | backgroundColor = .secondarySystemBackground
34 | } else {
35 | backgroundColor = .white
36 | }
37 | layer.cornerRadius = NativeAppearance.Corners.readable_area
38 | textAlignment = .center
39 | clearButtonMode = .whileEditing
40 | contentMode = .scaleAspectFit
41 | font = .preferredFont(forTextStyle: .title2, weight: .bold, addPoints: .zero)
42 | adjustsFontSizeToFitWidth = true
43 | minimumFontSize = 16
44 | insets = .init(horizontal: 48, vertical: 14)
45 | }
46 |
47 | // MARK: - Lifecycle
48 |
49 | open override func tintColorDidChange() {
50 | super.tintColorDidChange()
51 | textColor = tintColor
52 | }
53 |
54 | // MARK: - Layout
55 |
56 | /**
57 | NativeUIKit: Layout wrapper. Native way for layout button.
58 | */
59 | open func layout(y: CGFloat) {
60 | guard let superview = self.superview else { return }
61 | sizeToFit()
62 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
63 | frame.setWidth(width)
64 | setXCenter()
65 | frame.origin.y = y
66 | }
67 |
68 | /**
69 | NativeUIKit: Layout wrapper. Native way for layout button.
70 | */
71 | open func layout(maxY: CGFloat) {
72 | guard let superview = self.superview else { return }
73 | sizeToFit()
74 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
75 | frame.setWidth(width)
76 | setXCenter()
77 | frame.setMaxY(maxY)
78 | }
79 | }
80 | #endif
81 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/xcshareddata/xcschemes/iOS Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Table/Header/NativeHeaderTableController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | @available(iOS 13.0, *)
28 | open class NativeHeaderTableController: SPDiffableTableController {
29 |
30 | // MARK: - Public
31 |
32 | open var headerContainerView: HeaderContainerView
33 |
34 | // MARK: - Init
35 |
36 | public init(style: UITableView.Style, headerView: UIView) {
37 | self.headerContainerView = HeaderContainerView(contentView: headerView)
38 | super.init(style: style)
39 | }
40 |
41 | public required init?(coder: NSCoder) {
42 | fatalError("init(coder:) has not been implemented")
43 | }
44 |
45 | // MARK: - Lifecycle
46 |
47 | open override func viewDidLoad() {
48 | super.viewDidLoad()
49 | headerContainerView.setWidthAndFit(width: view.frame.width)
50 | tableView.tableHeaderView = headerContainerView
51 | }
52 |
53 | // MARK: - Layout
54 |
55 | open override func viewDidLayoutSubviews() {
56 | super.viewDidLayoutSubviews()
57 | headerContainerView.contentView.layoutMargins.left = tableView.layoutMargins.left
58 | headerContainerView.contentView.layoutMargins.right = tableView.layoutMargins.right
59 | headerContainerView.setWidthAndFit(width: view.frame.width)
60 | if cachedHeaderHeight != headerContainerView.frame.height {
61 | cachedHeaderHeight = headerContainerView.frame.height
62 | DispatchQueue.main.async { [weak self] in
63 | guard let self = self else { return }
64 | self.diffableDataSource?.updateLayout(animated: true, completion: nil)
65 | }
66 | }
67 | }
68 |
69 | private var cachedHeaderHeight: CGFloat? = nil
70 |
71 | // MARK: - Public
72 |
73 | open func setSpaceBetweenHeaderAndCells(_ value: CGFloat) {
74 | headerContainerView.layoutMargins.bottom = value
75 | }
76 | }
77 | #endif
78 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Navigation/NativeNavigationController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeNavigationController: SPNavigationController {
27 |
28 | // MARK: - Views
29 |
30 | open var mimicrateToolBarView: NativeMimicrateToolBarView? = nil {
31 | willSet {
32 | if let toolBarView = mimicrateToolBarView {
33 | toolBarView.removeFromSuperview()
34 | }
35 | }
36 | didSet {
37 | if let toolBarView = mimicrateToolBarView {
38 | view.addSubview(toolBarView)
39 | }
40 | }
41 | }
42 |
43 | open override func setToolbarHidden(_ hidden: Bool, animated: Bool) {
44 | if let barView = mimicrateToolBarView {
45 | if animated {
46 |
47 | if barView.isHidden && !hidden {
48 | barView.isHidden = false
49 | barView.alpha = .zero
50 | }
51 |
52 | UIView.animate(withDuration: 0.12, delay: .zero, options: [.beginFromCurrentState, .curveEaseInOut], animations: {
53 | barView.alpha = hidden ? .zero : 1
54 | }) { completed in
55 | barView.isHidden = hidden
56 | }
57 | } else {
58 | barView.isHidden = hidden
59 | }
60 | } else {
61 | super.setToolbarHidden(hidden, animated: animated)
62 | }
63 | }
64 |
65 | // MARK: - Layout
66 |
67 | open override func viewDidLayoutSubviews() {
68 | super.viewDidLayoutSubviews()
69 | if let toolBarView = mimicrateToolBarView {
70 | toolBarView.layoutMargins.bottom = systemSafeAreaInsets.bottom + 16
71 | toolBarView.setWidthAndFit(width: view.frame.width)
72 | toolBarView.frame.setMaxY(view.frame.height)
73 | let toolBarFrameFitHeight = toolBarView.frame.height - systemSafeAreaInsets.bottom
74 | if additionalSafeAreaInsets.bottom != toolBarFrameFitHeight {
75 | additionalSafeAreaInsets.bottom = toolBarFrameFitHeight
76 | }
77 | }
78 | }
79 | }
80 | #endif
81 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Onboarding/Actinos/NativeOnboardingActionsController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeOnboardingActionsController: NativeHeaderController {
27 |
28 | private var views: [NativeOnbiardingActionButton] = []
29 |
30 | // MARK: - Init
31 |
32 | public init(
33 | iconImage: UIImage?,
34 | title: String,
35 | subtitle: String
36 | ) {
37 | super.init(image: iconImage, title: title, subtitle: subtitle)
38 | }
39 |
40 | public required init?(coder: NSCoder) {
41 | fatalError("init(coder:) has not been implemented")
42 | }
43 |
44 | // MARK: - Lifecycle
45 |
46 | open override func viewDidLoad() {
47 | super.viewDidLoad()
48 | if #available(iOS 13.0, *) {
49 | self.view.backgroundColor = .systemBackground
50 | } else {
51 | view.backgroundColor = .white
52 | }
53 | scrollView.addSubviews(views)
54 | }
55 |
56 | open func setActions(_ models: [NativeOnbiardingActionButton.ActionModel]) {
57 | // Clean old
58 | views.forEach({ $0.removeFromSuperview() })
59 | views.removeAll()
60 |
61 | // Add new
62 | views = models.map({ NativeOnbiardingActionButton(with: $0) })
63 |
64 | // Added like subviews
65 | if isViewLoaded {
66 | scrollView.addSubviews(views)
67 | }
68 | }
69 |
70 | // MARK: - Layout
71 |
72 | open override func viewDidLayoutSubviews() {
73 | super.viewDidLayoutSubviews()
74 | var currentYPosition = headerView.frame.maxY + NativeLayout.Spaces.default_double
75 | let elementWidth: CGFloat = min(scrollView.readableWidth, 320)
76 | for (_, itemView) in views.enumerated() {
77 | itemView.setWidthAndFit(width: elementWidth)
78 | itemView.setXCenter()
79 | itemView.frame.origin.y = currentYPosition
80 | currentYPosition = itemView.frame.maxY + NativeLayout.Spaces.default_half
81 | }
82 | scrollView.contentSize = .init(width: scrollView.frame.width, height: views.last?.frame.maxY ?? .zero)
83 | }
84 | }
85 | #endif
86 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controls/Buttons/NativeSmallActionButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: Small action button.
28 | Using inside cells.
29 | */
30 | open class NativeSmallActionButton: SPDimmedButton {
31 |
32 | // MARK: - Init
33 |
34 | open override func commonInit() {
35 | super.commonInit()
36 | titleLabel?.font = UIFont.preferredFont(forTextStyle: .subheadline, weight: .bold, addPoints: -1)
37 | titleLabel?.numberOfLines = 1
38 | titleImageInset = 6
39 | contentEdgeInsets = .init(horizontal: 10, vertical: 6)
40 | }
41 |
42 | // MARK: - Public
43 |
44 | /**
45 | NativeUIKit: Wrapper of set content and color of button.
46 |
47 | - parameter title: Text which using like title.
48 | - parameter icon: Object of `UIImage`, using like icon. Usually Apple doesn't use icon in this button.
49 | - parameter colorise: Color of button in default state.
50 | */
51 | public func set(title: String, icon: UIImage? = nil, colorise: SPDimmedButton.Colorise) {
52 | setTitle(title)
53 | if let icon = icon {
54 | setImage(icon.alwaysTemplate)
55 | }
56 | applyDefaultAppearance(with: colorise)
57 | }
58 |
59 | // MARK: - Layout
60 |
61 | open override func layoutSubviews() {
62 | super.layoutSubviews()
63 | roundMinimumSide()
64 | }
65 |
66 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
67 | let superSize = super.sizeThatFits(size)
68 | var width = superSize.width
69 | let minimumWidth: CGFloat = 70
70 | if width < minimumWidth { width = minimumWidth }
71 |
72 | var height = superSize.height
73 | if let titleLabel = titleLabel, let imageView = imageView, let _ = imageView.image {
74 | if titleLabel.frame.height > .zero && imageView.frame.height > .zero {
75 | let imageCorrection = imageView.frame.height - titleLabel.frame.height
76 | height -= imageCorrection
77 | }
78 | }
79 |
80 | return CGSize(width: width, height: height)
81 | }
82 |
83 | // MARK: - Ovveride
84 |
85 | open override func setTitle(_ title: String?, for state: UIControl.State) {
86 | super.setTitle(title, for: state)
87 | }
88 | }
89 | #endif
90 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controls/Buttons/NativeMediumActionButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: Medium action button.
28 | You see it in Apply Music play and shuffle buttons.
29 | */
30 | open class NativeMediumActionButton: SPDimmedButton {
31 |
32 | // MARK: - Init
33 |
34 | open override func commonInit() {
35 | super.commonInit()
36 | titleLabel?.font = UIFont.preferredFont(forTextStyle: .body, weight: .semibold, addPoints: .zero)
37 | titleLabel?.numberOfLines = 1
38 | titleImageInset = 8
39 | contentEdgeInsets = .init(horizontal: 15, vertical: 15)
40 | roundCorners(radius: 12)
41 | }
42 |
43 | // MARK: - Public
44 |
45 | /**
46 | NativeUIKit: Wrapper of set content and color of button.
47 |
48 | - parameter title: Text which using like title.
49 | - parameter icon: Object of `UIImage`, using like icon. Usually Apple doesn't use icon in this button.
50 | - parameter colorise: Color of button in default state.
51 | */
52 | public func set(title: String, icon: UIImage? = nil, colorise: SPDimmedButton.Colorise) {
53 | setTitle(title)
54 | if let icon = icon {
55 | setImage(icon.alwaysTemplate)
56 | }
57 | applyDefaultAppearance(with: colorise)
58 | }
59 |
60 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
61 | let superSize = super.sizeThatFits(size)
62 | let width = superSize.width
63 |
64 | var height = superSize.height
65 | if let titleLabel = titleLabel, let imageView = imageView, let _ = imageView.image {
66 | if titleLabel.frame.height > .zero && imageView.frame.height > .zero {
67 | let imageCorrection = imageView.frame.height - titleLabel.frame.height
68 | height -= imageCorrection
69 | }
70 | }
71 |
72 | return CGSize(width: width, height: height)
73 | }
74 |
75 | // MARK: - Wrappers
76 |
77 | public static var defaultCornerRadius: CGFloat {
78 | let button = NativeMediumActionButton()
79 | return button.layer.cornerRadius
80 | }
81 |
82 | public static var defaultHeight: CGFloat {
83 | let button = NativeMediumActionButton()
84 | button.setTitle(.space)
85 | button.sizeToFit()
86 | return button.frame.height
87 | }
88 | }
89 | #endif
90 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Views/NativeLargeHeaderView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2020 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPDiffable
26 |
27 | open class NativeLargeHeaderView: SPView {
28 |
29 | // MARK: - Views
30 |
31 | public let titleLabel = SPLabel().do {
32 | $0.font = UIFont.preferredFont(forTextStyle: .title2, weight: .semibold)
33 | if #available(iOS 13.0, *) {
34 | $0.textColor = .label
35 | } else {
36 | $0.textColor = .black
37 | }
38 | }
39 |
40 | public let button = SPDimmedButton().do {
41 | $0.applyDefaultAppearance(with: .tintedContent)
42 | }
43 |
44 | // MARK: - Init
45 |
46 | open override func commonInit() {
47 | super.commonInit()
48 | layoutMargins = .init(top: NativeLayout.Spaces.default_double, left: .zero, bottom: 14, right: .zero)
49 | insetsLayoutMarginsFromSafeArea = false
50 | preservesSuperviewLayoutMargins = false
51 | addSubviews(titleLabel, button)
52 | }
53 |
54 | // MARK: - Layout
55 |
56 | open func layout(y: CGFloat) {
57 | guard let superview = self.superview else { return }
58 | setWidthAndFit(width: superview.layoutWidth)
59 | setXCenter()
60 | frame.origin.y = y
61 | }
62 |
63 | open override func layoutSubviews() {
64 | super.layoutSubviews()
65 | titleLabel.layoutDynamicHeight(
66 | x: layoutMargins.left,
67 | y: layoutMargins.top,
68 | width: layoutWidth
69 | )
70 | button.sizeToFit()
71 | button.setMaxXToSuperviewRightMargin()
72 | button.center.y = titleLabel.center.y
73 | }
74 |
75 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
76 | let superSize = super.sizeThatFits(size)
77 | layoutSubviews()
78 | return .init(width: superSize.width, height: titleLabel.frame.maxY + layoutMargins.bottom)
79 | }
80 |
81 | // MARK: - Private
82 |
83 | var diffableButtonAction: (()->Void)? = nil {
84 | didSet {
85 | if let _ = diffableButtonAction {
86 | self.button.addTarget(self, action: #selector(self.diffableButtonTargetAction), for: .touchUpInside)
87 | } else {
88 | self.button.removeTargetsAndActions()
89 | }
90 | }
91 | }
92 |
93 | @objc func diffableButtonTargetAction() {
94 | self.diffableButtonAction?()
95 | }
96 | }
97 | #endif
98 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Onboarding/NativeOnboardingController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPPageController
26 |
27 | open class NativeOnboardingController: SPPageController, NativeOnboardingManagerDelegate {
28 |
29 | private let controllers: [UIViewController]
30 | private let completion: SPCompletion
31 |
32 | // MARK: - Init
33 |
34 | public init(controllers: [UIViewController], completion: @escaping SPCompletion) {
35 |
36 | self.controllers = controllers
37 | self.completion = completion
38 |
39 | var childControllers: [UIViewController] = []
40 | for controller in controllers {
41 | let navigationController = NativeNavigationController(rootViewController: controller)
42 | navigationController.inheritLayoutMarginsForСhilds = true
43 | navigationController.inheritLayoutMarginsForNavigationBar = true
44 | navigationController.view.preservesSuperviewLayoutMargins = true
45 | childControllers.append(navigationController)
46 | }
47 |
48 | super.init(childControllers: childControllers, system: .page)
49 |
50 | controllers.forEach { controller in
51 | let onboardingChildController = controller as! NativeOnboardingChildInterface
52 | onboardingChildController.onboardingManagerDelegate = self
53 | }
54 |
55 | allowScroll = false
56 | allowDismissWithGester = false
57 | }
58 |
59 | public required init?(coder: NSCoder) {
60 | fatalError("init(coder:) has not been implemented")
61 | }
62 |
63 | // MARK: - OnboardingManagerDelegate
64 |
65 | public func onboardingActionComplete(for controller: UIViewController) {
66 | guard let index = controllers.firstIndex(of: controller) else { return }
67 | if index == (controllers.count - 1) {
68 | dismiss(animated: true) { [weak self] in
69 | self?.completion()
70 | }
71 | } else {
72 | safeScrollTo(index: index + 1, animated: true)
73 | }
74 | }
75 | }
76 |
77 | public protocol NativeOnboardingManagerDelegate: AnyObject {
78 |
79 | func onboardingActionComplete(for controller: UIViewController)
80 | }
81 |
82 | public protocol NativeOnboardingChildInterface: AnyObject {
83 |
84 | var onboardingManagerDelegate: NativeOnboardingManagerDelegate? { get set }
85 | }
86 | #endif
87 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/NativeBorderedView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: View with porder on some position.
28 | For change position check property.
29 | */
30 | open class NativeBorderedView: SPView {
31 |
32 | // MARK: - Data
33 |
34 | /**
35 | NativeUIKit: Border Position.
36 | */
37 | open var position: Position = .top {
38 | didSet {
39 | layoutSubviews()
40 | }
41 | }
42 |
43 | // MARK: - Views
44 |
45 | private let borderView = SPView().do {
46 | if #available(iOS 13.0, *) {
47 | $0.backgroundColor = .separator
48 | } else {
49 | $0.backgroundColor = .systemGray
50 | }
51 | }
52 |
53 | // MARK: - Init
54 |
55 | public init(position: Position) {
56 | self.position = position
57 | super.init()
58 | }
59 |
60 | public required init?(coder aDecoder: NSCoder) {
61 | super.init(coder: aDecoder)
62 | }
63 |
64 | open override func commonInit() {
65 | super.commonInit()
66 | addSubview(borderView)
67 | }
68 |
69 | // MARK: - Actions
70 |
71 | /**
72 | NativeUIKit: Show or hide border.
73 |
74 | - parameter visible: New visible state of border.
75 | - parameter animated: State for apply changes animatable or not.
76 | */
77 | open func setBorderVisible(_ visible: Bool, animated: Bool) {
78 | let work = { [weak self] in
79 | guard let self = self else { return }
80 | self.borderView.alpha = visible ? 1 : 0
81 | }
82 | if animated {
83 | UIView.animate(withDuration: 0.3, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
84 | work()
85 | })
86 | } else {
87 | work()
88 | }
89 | }
90 |
91 | // MARK: - Layout
92 |
93 | open override func layoutSubviews() {
94 | super.layoutSubviews()
95 | borderView.frame.setWidth(frame.width)
96 | borderView.frame.setHeight(0.5)
97 | borderView.frame.origin.x = 0
98 | switch position {
99 | case .top:
100 | borderView.frame.origin.y = 0
101 | case .bottom:
102 | borderView.frame.setMaxY(frame.height)
103 | }
104 | }
105 |
106 | // MARK: - Models
107 |
108 | public enum Position {
109 |
110 | case top
111 | case bottom
112 | }
113 | }
114 | #endif
115 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Bars/ToolBar/LargeAction/NativeLargeActionToolBarView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeLargeActionToolBarView: NativeMimicrateToolBarView {
27 |
28 | // MARK: - Views
29 |
30 | public let activityIndicatorView = UIActivityIndicatorView()
31 |
32 | public let actionButton = NativeLargeActionButton().do {
33 | $0.applyDefaultAppearance(with: .tintedColorful)
34 | }
35 |
36 | public let footerLabel = SPLabel().do {
37 | $0.font = .preferredFont(forTextStyle: .footnote)
38 | $0.numberOfLines = .zero
39 | if #available(iOS 13.0, *) {
40 | $0.textColor = .secondaryLabel
41 | } else {
42 | $0.textColor = .black.alpha(0.5)
43 | }
44 | }
45 |
46 | // MARK: - Init
47 |
48 | open override func commonInit() {
49 | super.commonInit()
50 | addSubview(activityIndicatorView)
51 | addSubview(actionButton)
52 | addSubview(footerLabel)
53 | }
54 |
55 | // MARK: - Actions
56 |
57 | open func setLoading(_ state: Bool) {
58 | if state {
59 | activityIndicatorView.startAnimating()
60 | actionButton.isHidden = true
61 | footerLabel.isHidden = true
62 | } else {
63 | activityIndicatorView.stopAnimating()
64 | actionButton.isHidden = false
65 | footerLabel.isHidden = false
66 | }
67 | }
68 |
69 | // MARK: - Layout
70 |
71 | internal let footerLeftInset: CGFloat = 20
72 |
73 | open override func layoutSubviews() {
74 | super.layoutSubviews()
75 | actionButton.layout(y: layoutMargins.top)
76 | if footerLabel.text != nil {
77 | footerLabel.layoutDynamicHeight(x: layoutMargins.left + footerLeftInset, y: actionButton.frame.maxY + 12, width: layoutWidth - footerLeftInset)
78 | }
79 |
80 | let contentHeight: CGFloat = {
81 | if footerLabel.text == nil {
82 | return actionButton.frame.maxY
83 | } else {
84 | return footerLabel.frame.maxY
85 | }
86 | }()
87 | activityIndicatorView.setXCenter()
88 | activityIndicatorView.center.y = contentHeight / 2
89 | }
90 |
91 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
92 | layoutSubviews()
93 | if footerLabel.text == nil {
94 | return .init(width: size.width, height: actionButton.frame.maxY + layoutMargins.bottom)
95 | } else {
96 | return .init(width: size.width, height: footerLabel.frame.maxY + layoutMargins.bottom)
97 | }
98 | }
99 | }
100 | #endif
101 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Onboarding/Features/NativeOnboardingFeaturesController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeOnboardingFeaturesController: NativeHeaderController {
27 |
28 | private var views: [NativeOnboardingFeatureView] = []
29 |
30 | // MARK: - Init
31 |
32 | public init(
33 | iconImage: UIImage?,
34 | title: String,
35 | subtitle: String
36 | ) {
37 | super.init(image: iconImage, title: title, subtitle: subtitle)
38 | }
39 |
40 | public required init?(coder: NSCoder) {
41 | fatalError("init(coder:) has not been implemented")
42 | }
43 |
44 | // MARK: - Lifecycle
45 |
46 | open override func viewDidLoad() {
47 | super.viewDidLoad()
48 | if #available(iOS 13.0, *) {
49 | self.view.backgroundColor = .systemBackground
50 | } else {
51 | view.backgroundColor = .white
52 | }
53 | scrollView.addSubviews(views)
54 | }
55 |
56 | open func setFeatures(_ models: [NativeOnboardingFeatureView.FeatureModel]) {
57 | // Clean old
58 | views.forEach({ $0.removeFromSuperview() })
59 | views.removeAll()
60 |
61 | // Add new
62 | views = models.map({ NativeOnboardingFeatureView(with: $0) })
63 |
64 | // Added like subviews
65 | if isViewLoaded {
66 | scrollView.addSubviews(views)
67 | }
68 | }
69 |
70 | // MARK: - Layout
71 |
72 | open override func viewDidLayoutSubviews() {
73 | super.viewDidLayoutSubviews()
74 | var currentYPosition = headerView.frame.maxY + NativeLayout.Spaces.default_double
75 | for (_, itemView) in views.enumerated() {
76 | itemView.setWidthAndFit(width: scrollView.readableWidth)
77 | itemView.setXCenter()
78 | itemView.frame.origin.y = currentYPosition
79 | currentYPosition = itemView.frame.maxY + NativeLayout.Spaces.default_half
80 | }
81 | scrollView.contentSize = .init(width: scrollView.frame.width, height: views.last?.frame.maxY ?? .zero)
82 | }
83 |
84 | public func scrollViewDidScroll(_ scrollView: UIScrollView) {
85 | for itemView in views {
86 | let progress = progressForFeatureView(itemView)
87 | itemView.setProgress(progress)
88 | }
89 | }
90 |
91 | private func progressForFeatureView(_ view: NativeOnboardingFeatureView) -> CGFloat {
92 | let offsetY = scrollView.contentOffset.y + scrollView.safeAreaInsets.top + scrollView.frame.height - scrollView.safeAreaInsets.bottom
93 | let correction: CGFloat = NativeLayout.Spaces.Scroll.bottom_inset_reach_end
94 | let topSafeArea = scrollView.safeAreaInsets.top + correction
95 | let startPosition = view.frame.origin.y + topSafeArea
96 | let progress = (offsetY - startPosition) / view.frame.height
97 | if progress < .zero { return .zero }
98 | if progress > 1 { return 1 }
99 | return progress
100 | }
101 | }
102 | #endif
103 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Table/Empty/NativeEmptyTableViewCell.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativeEmptyTableViewCell: SPTableViewCell {
27 |
28 | // MARK: - Data
29 |
30 | open var verticalMargins: Margins = .medium {
31 | didSet {
32 | contentView.layoutMargins.top = self.verticalMargins.value
33 | contentView.layoutMargins.bottom = self.verticalMargins.value
34 | }
35 | }
36 |
37 | // MARK: - Views
38 |
39 | public let placeholderView = NativePlaceholderView().do {
40 | $0.isUserInteractionEnabled = false
41 | }
42 |
43 | // MARK: - Init
44 |
45 | open override func commonInit() {
46 | super.commonInit()
47 | selectionStyle = .none
48 | contentView.addSubview(placeholderView)
49 | updateBackgroundColorByParent()
50 | }
51 |
52 | // MARK: - Lifecycle
53 |
54 | open override func tintColorDidChange() {
55 | super.tintColorDidChange()
56 | updateBackgroundColorByParent()
57 | }
58 |
59 | // MARK: - Layout
60 |
61 | open override func layoutSubviews() {
62 | super.layoutSubviews()
63 | placeholderView.frame.origin.y = contentView.layoutMargins.top
64 | placeholderView.setWidthAndFit(width: contentView.layoutWidth)
65 | placeholderView.setXCenter()
66 | }
67 |
68 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
69 | let superSize = super.sizeThatFits(size)
70 | layoutSubviews()
71 | let calculatedHeight = placeholderView.frame.maxY + contentView.layoutMargins.bottom
72 | let bottomInset = calculatedHeight * (1 - 0.94)
73 | return .init(width: superSize.width, height: calculatedHeight + bottomInset)
74 | }
75 |
76 | // MARK: - Actions
77 |
78 | private func updateBackgroundColorByParent() {
79 | if #available(iOS 13.0, *) {
80 | backgroundColor = UIColor.systemDownedGroupedBackground
81 | }
82 | /*if let superView = self.superview?.superview {
83 | let superViewBackgroundColor = superView.backgroundColor ?? .clear
84 | if superViewBackgroundColor == .systemGroupedBackground {
85 | backgroundColor = UIColor.init(
86 | light: superViewBackgroundColor.mixWithColor(.darkGray, amount: 0.09).mixWithColor(.systemBlue, amount: 0.01),
87 | dark: .secondarySystemGroupedBackground.alpha(0.7)
88 | )
89 | } else {
90 | // Here not implemented becouse not using never for now.
91 | backgroundColor = .red
92 | }
93 | }*/
94 | }
95 |
96 | // MARK: - Models
97 |
98 | public enum Margins {
99 |
100 | case small
101 | case medium
102 | case large
103 |
104 | var value: CGFloat {
105 | switch self {
106 | case .small: return 16
107 | case .medium: return 32
108 | case .large: return 48
109 | }
110 | }
111 | }
112 | }
113 | #endif
114 |
--------------------------------------------------------------------------------
/Example App/NativeUIKit.xcodeproj/xcshareddata/xcschemes/watchOS Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
57 |
61 |
67 |
68 |
69 |
70 |
76 |
80 |
86 |
87 |
88 |
89 |
95 |
96 |
97 |
98 |
100 |
101 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controls/Buttons/NativeLargeActionButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: Large action button.
28 | Usually using at bottom of screen.
29 | */
30 | open class NativeLargeActionButton: SPDimmedButton {
31 |
32 | // MARK: - Init
33 |
34 | open override func commonInit() {
35 | super.commonInit()
36 | insetsLayoutMarginsFromSafeArea = false
37 | preservesSuperviewLayoutMargins = false
38 | titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline, addPoints: 1)
39 | titleLabel?.numberOfLines = 1
40 | highlightOpacity = NativeAppearance.actionable_element_highlight_opacity
41 | titleImageInset = 6
42 | contentEdgeInsets = .init(horizontal: 10, vertical: 12)
43 | roundCorners(radius: NativeAppearance.Corners.readable_area)
44 | }
45 |
46 | // MARK: - Public
47 |
48 | /**
49 | NativeUIKit: Wrapper of set content and color of button.
50 |
51 | - parameter title: Text which using like title.
52 | - parameter icon: Object of `UIImage`, using like icon.
53 | - parameter colorise: Color of button in default state.
54 | */
55 | public func set(title: String, icon: UIImage?, colorise: SPDimmedButton.Colorise) {
56 | setTitle(title)
57 | if let icon = icon {
58 | setImage(icon.alwaysTemplate)
59 | }
60 | applyDefaultAppearance(with: colorise)
61 | }
62 |
63 | // MARK: - Layout
64 |
65 | /**
66 | NativeUIKit: Layout wrapper. Native way for layout button.
67 | */
68 | open func layout(y: CGFloat) {
69 | guard let superview = self.superview else { return }
70 | sizeToFit()
71 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
72 | frame.setWidth(width)
73 | setXCenter()
74 | frame.origin.y = y
75 | }
76 |
77 | /**
78 | NativeUIKit: Layout wrapper. Native way for layout button.
79 | */
80 | open func layout(maxY: CGFloat) {
81 | guard let superview = self.superview else { return }
82 | sizeToFit()
83 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
84 | frame.setWidth(width)
85 | setXCenter()
86 | frame.setMaxY(maxY)
87 | }
88 |
89 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
90 | let superSize = super.sizeThatFits(size)
91 | let width = superSize.width
92 |
93 | var height = superSize.height
94 | if let titleLabel = titleLabel, let imageView = imageView, let _ = imageView.image {
95 | if titleLabel.frame.height > .zero && imageView.frame.height > .zero {
96 | let imageCorrection = imageView.frame.height - titleLabel.frame.height
97 | height -= imageCorrection
98 | }
99 | }
100 |
101 | return CGSize(width: width, height: height)
102 | }
103 |
104 | // MARK: - Wrappers
105 |
106 | public static var defaultCornerRadius: CGFloat {
107 | let button = NativeLargeActionButton()
108 | return button.layer.cornerRadius
109 | }
110 |
111 | public static var defaultHeight: CGFloat {
112 | let button = NativeLargeActionButton()
113 | button.setTitle(.space)
114 | button.sizeToFit()
115 | return button.frame.height
116 | }
117 | }
118 | #endif
119 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Onboarding/Features/NativeOnboardingFeatureView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | public class NativeOnboardingFeatureView: SPView {
27 |
28 | // MARK: - Data
29 |
30 | let model: FeatureModel
31 |
32 | // MARK: - Views
33 |
34 | let iconView = SPImageView().do {
35 | $0.contentMode = .scaleAspectFit
36 | }
37 |
38 | let titleLabel = SPLabel().do {
39 | $0.font = .preferredFont(forTextStyle: .title3, weight: .semibold)
40 | if #available(iOS 13.0, *) {
41 | $0.textColor = .label
42 | } else {
43 | $0.textColor = .black
44 | }
45 | $0.numberOfLines = .zero
46 | }
47 |
48 | let descriptionLabel = SPLabel().do {
49 | $0.font = .preferredFont(forTextStyle: .body)
50 | if #available(iOS 13.0, *) {
51 | $0.textColor = .secondaryLabel
52 | } else {
53 | $0.textColor = .black
54 | }
55 | $0.numberOfLines = .zero
56 | }
57 |
58 | // MARK: - Init
59 |
60 | init(with model: FeatureModel) {
61 | self.model = model
62 | super.init()
63 | iconView.image = model.iconImage
64 | titleLabel.text = model.title
65 | descriptionLabel.text = model.description
66 | }
67 |
68 | required init?(coder aDecoder: NSCoder) {
69 | fatalError("init(coder:) has not been implemented")
70 | }
71 |
72 | public override func commonInit() {
73 | super.commonInit()
74 | backgroundColor = .clear
75 | roundCorners(radius: NativeLayout.Spaces.default_less)
76 | layoutMargins = .init(horizontal: NativeLayout.Spaces.default_more, vertical: NativeLayout.Spaces.default_more)
77 | addSubviews(iconView, titleLabel, descriptionLabel)
78 | }
79 |
80 | // MARK: - Layout
81 |
82 | public override func layoutSubviews() {
83 | super.layoutSubviews()
84 | iconView.frame = .init(side: 42)
85 | iconView.frame.origin.y = layoutMargins.top
86 | iconView.frame.origin.x = layoutMargins.left
87 |
88 | let labelWidth = layoutWidth - iconView.frame.width - NativeLayout.Spaces.default
89 |
90 | titleLabel.layoutDynamicHeight(width: labelWidth)
91 | titleLabel.setMaxXToSuperviewRightMargin()
92 | titleLabel.frame.origin.y = layoutMargins.top
93 |
94 | descriptionLabel.layoutDynamicHeight(width: labelWidth)
95 | descriptionLabel.frame.origin.x = titleLabel.frame.origin.x
96 | descriptionLabel.frame.origin.y = titleLabel.frame.maxY + NativeLayout.Spaces.step
97 | }
98 |
99 | public override func sizeThatFits(_ size: CGSize) -> CGSize {
100 | layoutSubviews()
101 | return .init(width: size.width, height: descriptionLabel.frame.maxY + layoutMargins.bottom)
102 | }
103 |
104 | // MARK: - Actions
105 |
106 | func setProgress(_ value: CGFloat) {
107 | if #available(iOS 13.0, *) {
108 | self.backgroundColor = .secondarySystemBackground.alpha(1 - value)
109 | }
110 | }
111 |
112 | // MARK: - Models
113 |
114 | /**
115 | Wrapper of data for feature model.
116 |
117 | - important: Recomended use custom tint color for icons like native.
118 | */
119 | public class FeatureModel {
120 |
121 | let iconImage: UIImage
122 | let title: String
123 | let description: String
124 |
125 | public init(iconImage: UIImage, title: String, description: String) {
126 | self.iconImage = iconImage
127 | self.title = title
128 | self.description = description
129 | }
130 | }
131 | }
132 | #endif
133 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Labels/NativeModalHeaderView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | /**
27 | NativeUIKit: Usually use in modal screen with large title and subtitle.
28 | Image is optional.
29 | */
30 | open class NativeModalHeaderView: SPView {
31 |
32 | // MARK: - Views
33 |
34 | public let iconImageView = SPImageView().do {
35 | $0.contentMode = .scaleAspectFit
36 | $0.tintColor = UIColor.tint
37 | }
38 |
39 | public let titleLabel = SPLabel().do {
40 | $0.numberOfLines = .zero
41 | $0.font = UIFont.preferredFont(forTextStyle: .largeTitle, weight: .bold)
42 | if #available(iOS 13.0, *) {
43 | $0.textColor = .label
44 | } else {
45 | $0.textColor = .black
46 | }
47 | $0.textAlignment = .center
48 | }
49 |
50 | public let subtitleLabel = SPLabel().do {
51 | $0.numberOfLines = .zero
52 | $0.font = UIFont.preferredFont(forTextStyle: .body)
53 | if #available(iOS 13.0, *) {
54 | $0.textColor = .secondaryLabel
55 | } else {
56 | $0.textColor = .black.alpha(0.5)
57 | }
58 | $0.textAlignment = .center
59 | }
60 |
61 | // MARK: - Init
62 |
63 | public override init() {
64 | super.init()
65 | }
66 |
67 | public init(image: UIImage?, title: String, subtitle: String) {
68 | super.init()
69 | titleLabel.text = title
70 | subtitleLabel.text = subtitle
71 | iconImageView.image = image
72 | }
73 |
74 | public required init?(coder aDecoder: NSCoder) {
75 | fatalError("init(coder:) has not been implemented")
76 | }
77 |
78 | open override func commonInit() {
79 | super.commonInit()
80 | backgroundColor = .clear
81 | layoutMargins = .zero
82 | addSubview(titleLabel)
83 | addSubview(subtitleLabel)
84 | addSubview(iconImageView)
85 | }
86 |
87 | // MARK: - Layout
88 |
89 | /**
90 | NativeUIKit: Layout wrapper. Native way for layout button.
91 | */
92 | open func layout(y: CGFloat) {
93 | guard let superview = self.superview else { return }
94 | let width = min(superview.readableWidth, NativeLayout.Sizes.not_actionable_area_maximum_width)
95 | setWidthAndFit(width: width)
96 | setXCenter()
97 | frame.origin.y = y
98 | }
99 |
100 | /**
101 | NativeUIKit: Layout wrapper. Native way for layout button.
102 | */
103 | open func layout(maxY: CGFloat) {
104 | guard let superview = self.superview else { return }
105 | let width = min(superview.readableWidth, NativeLayout.Sizes.not_actionable_area_maximum_width)
106 | setWidthAndFit(width: width)
107 | setXCenter()
108 | frame.setMaxY(maxY)
109 | }
110 |
111 | open override func layoutSubviews() {
112 | super.layoutSubviews()
113 | iconImageView.frame = .init(side: NativeLayout.Spaces.default_double * 2)
114 | iconImageView.setXCenter()
115 | iconImageView.frame.origin.y = layoutMargins.top
116 |
117 | if let _ = iconImageView.image {
118 | titleLabel.layoutDynamicHeight(x: .zero, y: iconImageView.frame.maxY + 12, width: layoutWidth)
119 | } else {
120 | titleLabel.layoutDynamicHeight(x: .zero, y: .zero, width: layoutWidth)
121 | }
122 |
123 | subtitleLabel.layoutDynamicHeight(x: .zero, y: titleLabel.frame.maxY + 4, width: titleLabel.frame.width)
124 | }
125 |
126 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
127 | layoutSubviews()
128 | return .init(width: size.width, height: subtitleLabel.frame.maxY + layoutMargins.bottom)
129 | }
130 | }
131 | #endif
132 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | hello@ivanvorobei.io.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Profile/NativeProfileHeaderView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | @available(iOS 13.0, *)
27 | open class NativeProfileHeaderView: SPView {
28 |
29 | // MARK: - Public
30 |
31 | public let avatarView = NativeAvatarView().do {
32 | $0.avatarAppearance = .placeholder
33 | $0.isEditable = true
34 | }
35 |
36 | public let nameLabel = SPLabel().do {
37 | $0.font = UIFont.preferredFont(forTextStyle: .title2, weight: .semibold, addPoints: 2)
38 | $0.textColor = .label
39 | $0.numberOfLines = 1
40 | $0.textAlignment = .center
41 | // $0.adjustsFontSizeToFitWidth = true
42 | // $0.minimumScaleFactor = 0.5
43 | $0.text = nil
44 | }
45 |
46 | public let namePlaceholderLabel = SPLabel().do {
47 | $0.font = UIFont.preferredFont(forTextStyle: .title2, weight: .semibold, addPoints: 2)
48 | $0.textColor = .secondaryLabel
49 | $0.numberOfLines = 1
50 | $0.textAlignment = .center
51 | // $0.adjustsFontSizeToFitWidth = true
52 | // $0.minimumScaleFactor = 0.5
53 | $0.text = nil
54 | }
55 |
56 | // Add tap to clipboard
57 | public let emailButton = SPDimmedButton().do {
58 | $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body, weight: .regular, addPoints: -2)
59 | // $0.titleLabel?.adjustsFontSizeToFitWidth = true
60 | // $0.titleLabel?.minimumScaleFactor = 0.5
61 | $0.titleImageInset = 2
62 | $0.titleLabel?.textAlignment = .center
63 | }
64 |
65 | // MARK: - Private
66 |
67 | private var extendView = SPView()
68 |
69 | var nameTextObserer: NSKeyValueObservation?
70 |
71 | // MARK: - Init
72 |
73 | open override func commonInit() {
74 | super.commonInit()
75 | backgroundColor = .clear
76 | addSubviews([extendView, avatarView, nameLabel, namePlaceholderLabel, emailButton])
77 |
78 | layoutMargins = .init(
79 | top: NativeLayout.Spaces.default_half,
80 | left: NativeLayout.Spaces.default_double,
81 | bottom: NativeLayout.Spaces.default_half,
82 | right: NativeLayout.Spaces.default_double
83 | )
84 |
85 | self.nameLabel.isHidden = !(self.nameLabel == self.usingNameLabel)
86 | self.namePlaceholderLabel.isHidden = !(self.namePlaceholderLabel == self.usingNameLabel)
87 |
88 | nameTextObserer = nameLabel.observe(\.text) { [weak self] _, _ in
89 | guard let self = self else { return }
90 | self.nameLabel.isHidden = !(self.nameLabel == self.usingNameLabel)
91 | self.namePlaceholderLabel.isHidden = !(self.namePlaceholderLabel == self.usingNameLabel)
92 | }
93 | }
94 |
95 | // MARK: - Ovveride
96 |
97 | open override var backgroundColor: UIColor? {
98 | didSet {
99 | extendView.backgroundColor = backgroundColor
100 | }
101 | }
102 |
103 | // MARK: - Layout
104 |
105 | private var usingNameLabel: SPLabel {
106 | if nameLabel.text?.isEmptyContent ?? true {
107 | return namePlaceholderLabel
108 | } else {
109 | return nameLabel
110 | }
111 | }
112 |
113 | open override func layoutSubviews() {
114 | super.layoutSubviews()
115 | extendView.frame = .init(x: .zero, maxY: .zero, width: frame.width, height: 1000)
116 |
117 | avatarView.sizeToFit()
118 | avatarView.setXCenter()
119 | avatarView.frame.origin.y = layoutMargins.top
120 |
121 | let textWidth: CGFloat = layoutWidth * 0.8
122 |
123 | nameLabel.layoutDynamicHeight(width: textWidth)
124 | nameLabel.setXCenter()
125 | nameLabel.frame.origin.y = avatarView.frame.maxY + NativeLayout.Spaces.default_half
126 |
127 | namePlaceholderLabel.layoutDynamicHeight(width: textWidth)
128 | namePlaceholderLabel.setXCenter()
129 | namePlaceholderLabel.frame.origin.y = nameLabel.frame.origin.y
130 |
131 | emailButton.sizeToFit()
132 | if emailButton.frame.width > textWidth {
133 | emailButton.frame.setWidth(textWidth)
134 | }
135 | emailButton.setXCenter()
136 | emailButton.frame.origin.y = usingNameLabel.frame.maxY
137 | }
138 |
139 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
140 | layoutSubviews()
141 | return .init(width: frame.width, height: emailButton.frame.maxY + layoutMargins.bottom)
142 | }
143 | }
144 | #endif
145 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Views/NativePromoView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 | import SPPerspective
26 |
27 | open class NativePromoView: SPView {
28 |
29 | // MARK: - Views
30 |
31 | public let titleLabel = SPLabel().do {
32 | $0.font = UIFont.preferredFont(forTextStyle: .title2, weight: .semibold)
33 | if #available(iOS 13.0, *) {
34 | $0.textColor = .label
35 | } else {
36 | $0.textColor = .black
37 | }
38 | $0.numberOfLines = .zero
39 | $0.textAlignment = .center
40 | }
41 |
42 | public let descriptionLabel = SPLabel().do {
43 | $0.font = UIFont.preferredFont(forTextStyle: .body, weight: .regular)
44 | if #available(iOS 13.0, *) {
45 | $0.textColor = .secondaryLabel
46 | } else {
47 | $0.textColor = .black.alpha(0.5)
48 | }
49 | $0.numberOfLines = .zero
50 | $0.textAlignment = .center
51 | }
52 |
53 | public let iconView = SPImageView().do {
54 | $0.backgroundColor = .clear
55 | }
56 |
57 | public let button = SPDimmedButton().do {
58 | $0.applyDefaultAppearance(with: .tintedContent)
59 | $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body, weight: .semibold, addPoints: 2)
60 | }
61 |
62 | public let areaView = SPView().do {
63 | if #available(iOS 13.0, *) {
64 | $0.backgroundColor = UIColor.secondarySystemBackground
65 | }
66 | $0.layer.cornerRadius = 15
67 | }
68 |
69 | // MARK: - Init
70 |
71 | open override func commonInit() {
72 | super.commonInit()
73 | layoutMargins = .zero
74 | addSubview(areaView)
75 | addSubview(titleLabel)
76 | addSubview(descriptionLabel)
77 | addSubview(iconView)
78 | addSubview(button)
79 | areaView.layoutMargins = .init(horizontal: 24, vertical: 24)
80 | iconView.applyPerspective(.iOS14WidgetAnimatable)
81 | }
82 |
83 | // MARK: - Layout
84 |
85 | open func layout(y: CGFloat) {
86 | guard let superview = self.superview else { return }
87 | var width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
88 | if (width == .zero) && (superview.layoutWidth != .zero) { width = superview.layoutWidth }
89 | setWidthAndFit(width: width)
90 | setXCenter()
91 | frame.origin.y = y
92 | }
93 |
94 | open override func layoutSubviews() {
95 | super.layoutSubviews()
96 | areaView.frame = .init(x: layoutMargins.left, y: layoutMargins.top, width: layoutWidth, height: areaView.frame.height)
97 |
98 | let labelsWidth = areaView.layoutWidth
99 |
100 | titleLabel.layoutDynamicHeight(width: labelsWidth)
101 | titleLabel.setXCenter()
102 | titleLabel.frame.origin.y = areaView.frame.origin.y + areaView.layoutMargins.top
103 |
104 | descriptionLabel.layoutDynamicHeight(width: labelsWidth)
105 | descriptionLabel.setXCenter()
106 | descriptionLabel.frame.origin.y = titleLabel.frame.maxY + 3
107 |
108 | let iconSideSize = min(titleLabel.frame.width * 0.5, 120)
109 | iconView.frame.setWidth(iconSideSize)
110 | iconView.frame.setHeight(iconSideSize)
111 | iconView.setXCenter()
112 | iconView.frame.origin.y = descriptionLabel.frame.maxY + 16
113 |
114 | areaView.frame.setHeight(iconView.frame.origin.y + iconView.frame.height / 2)
115 |
116 | button.sizeToFit()
117 | button.setXCenter()
118 | button.frame.origin.y = iconView.frame.maxY + 24
119 | }
120 |
121 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
122 | layoutSubviews()
123 | return .init(width: size.width, height: button.frame.maxY + layoutMargins.bottom)
124 | }
125 | }
126 |
127 | open class NativePromoContainerView: SPView {
128 |
129 | // MARK: - Views
130 |
131 | public let promoView = NativePromoView()
132 |
133 | // MARK: - Init
134 |
135 | open override func commonInit() {
136 | super.commonInit()
137 | layoutMargins = .zero
138 | addSubview(promoView)
139 | }
140 |
141 | // MARK: - Layout
142 |
143 | open override func layoutSubviews() {
144 | super.layoutSubviews()
145 | promoView.layout(y: layoutMargins.top)
146 | }
147 |
148 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
149 | layoutSubviews()
150 | return .init(width: size.width, height: promoView.frame.maxY + layoutMargins.bottom)
151 | }
152 | }
153 | #endif
154 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Controllers/Complex/Onboarding/Actinos/NativeOnbiardingActionButton.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | public class NativeOnbiardingActionButton: SPDimmedButton {
27 |
28 | // MARK: - Data
29 |
30 | private let model: ActionModel
31 |
32 | // MARK: - Views
33 |
34 | let disclouserIndicator = SPDimmedButton().do {
35 | if #available(iOS 13, *) {
36 | $0.setImage(.system("chevron.right", font: .preferredFont(forTextStyle: .body, weight: .medium)).alwaysTemplate)
37 | $0.tintColor = .tertiaryLabel
38 | }
39 | }
40 |
41 | let actionIconView = SPImageView().do {
42 | $0.contentMode = .scaleAspectFit
43 | }
44 |
45 | let actionTitleLabel = SPLabel().do {
46 | $0.font = .preferredFont(forTextStyle: .body, weight: .semibold)
47 | if #available(iOS 13.0, *) {
48 | $0.textColor = .label
49 | } else {
50 | $0.textColor = .black
51 | }
52 | $0.numberOfLines = .zero
53 | }
54 |
55 | let actionDescriptionLabel = SPLabel().do {
56 | $0.font = .preferredFont(forTextStyle: .subheadline)
57 | if #available(iOS 13.0, *) {
58 | $0.textColor = .secondaryLabel
59 | } else {
60 | $0.textColor = .black
61 | }
62 | $0.numberOfLines = .zero
63 | }
64 |
65 | // MARK: - Init
66 |
67 | init(with model: ActionModel) {
68 | self.model = model
69 | super.init()
70 | actionIconView.image = model.iconImage
71 | actionTitleLabel.text = model.title
72 | actionDescriptionLabel.text = model.description
73 |
74 | addTarget(self, action: #selector(self.didTap), for: .touchUpInside)
75 | }
76 |
77 | required init?(coder aDecoder: NSCoder) {
78 | fatalError("init(coder:) has not been implemented")
79 | }
80 |
81 | public override func commonInit() {
82 | super.commonInit()
83 | higlightStyle = .background
84 | if #available(iOS 13.0, *) {
85 | applyDefaultAppearance(with: .init(content: .label, background: .secondarySystemBackground))
86 | }
87 | roundCorners(radius: NativeLayout.Spaces.default_less)
88 | layoutMargins = .init(horizontal: NativeLayout.Spaces.default_more, vertical: NativeLayout.Spaces.default_more)
89 | addSubviews(actionIconView, actionTitleLabel, actionDescriptionLabel, disclouserIndicator)
90 | }
91 |
92 | // MARK: - Layout
93 |
94 | public override func layoutSubviews() {
95 | super.layoutSubviews()
96 | actionIconView.frame = .init(side: 28)
97 | actionIconView.frame.origin.x = layoutMargins.left
98 |
99 | disclouserIndicator.sizeToFit()
100 | disclouserIndicator.setMaxXToSuperviewRightMargin()
101 |
102 | let leftSpace: CGFloat = NativeLayout.Spaces.default_more
103 | let rightSpace: CGFloat = NativeLayout.Spaces.default
104 | let labelWidth = layoutWidth - actionIconView.frame.width - disclouserIndicator.frame.width - leftSpace - rightSpace
105 |
106 | actionTitleLabel.layoutDynamicHeight(width: labelWidth)
107 | actionTitleLabel.frame.origin.x = actionIconView.frame.maxX + leftSpace
108 | actionTitleLabel.frame.origin.y = layoutMargins.top
109 |
110 | actionDescriptionLabel.layoutDynamicHeight(width: labelWidth)
111 | actionDescriptionLabel.frame.origin.x = actionTitleLabel.frame.origin.x
112 | actionDescriptionLabel.frame.origin.y = actionTitleLabel.frame.maxY + NativeLayout.Spaces.step
113 |
114 | disclouserIndicator.setYCenter()
115 | actionIconView.setYCenter()
116 | }
117 |
118 | public override func sizeThatFits(_ size: CGSize) -> CGSize {
119 | layoutSubviews()
120 | return .init(width: size.width, height: actionDescriptionLabel.frame.maxY + layoutMargins.bottom)
121 | }
122 |
123 | // MARK: - Action
124 |
125 | @objc func didTap() {
126 | self.model.action()
127 | }
128 |
129 | // MARK: - Models
130 |
131 | /**
132 | Wrapper of data for action model.
133 |
134 | - important: Recomended save app tint color for icons like native.
135 | */
136 | public class ActionModel {
137 |
138 | let iconImage: UIImage
139 | let title: String
140 | let description: String
141 | let action: ()->Void
142 |
143 | public init(iconImage: UIImage, title: String, description: String, action: @escaping ()->Void) {
144 | self.iconImage = iconImage
145 | self.title = title
146 | self.description = description
147 | self.action = action
148 | }
149 | }
150 | }
151 | #endif
152 |
--------------------------------------------------------------------------------
/Sources/NativeUIKit/Views/NativePlaceholderView.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | // Copyright © 2021 Ivan Vorobei (hello@ivanvorobei.io)
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 |
22 | #if canImport(UIKit) && (os(iOS))
23 | import UIKit
24 | import SparrowKit
25 |
26 | open class NativePlaceholderView: SPButton {
27 |
28 | // MARK: - Views
29 |
30 | public let iconImageView = SPImageView().do {
31 | $0.contentMode = .scaleAspectFit
32 | }
33 |
34 | public let headerLabel = SPLabel().do {
35 | $0.numberOfLines = .zero
36 | $0.textAlignment = .center
37 | $0.font = UIFont.preferredFont(forTextStyle: .title1, weight: .bold)
38 | }
39 |
40 | public let descriptionLabel = SPLabel().do {
41 | $0.numberOfLines = .zero
42 | $0.textAlignment = .center
43 | $0.font = UIFont.preferredFont(forTextStyle: .body, weight: .regular)
44 | }
45 |
46 | // MARK: - Init
47 |
48 | public override init() {
49 | super.init()
50 | }
51 |
52 | public init(icon: UIImage, title: String, subtitle: String) {
53 | super.init()
54 | iconImageView.image = icon.alwaysTemplate
55 | headerLabel.text = title
56 | descriptionLabel.text = subtitle
57 | }
58 |
59 | public required init?(coder aDecoder: NSCoder) {
60 | fatalError("init(coder:) has not been implemented")
61 | }
62 |
63 | open override func commonInit() {
64 | super.commonInit()
65 | layoutMargins = .zero
66 | if #available(iOS 13.0, *) {
67 | tintColor = .tertiaryLabel
68 | } else {
69 | tintColor = UIColor.black.alpha(0.3)
70 | }
71 | backgroundColor = .clear
72 | iconImageView.tintColor = tintColor
73 | addSubview(iconImageView)
74 | headerLabel.textColor = tintColor
75 | addSubview(headerLabel)
76 | descriptionLabel.textColor = tintColor
77 | addSubview(descriptionLabel)
78 | }
79 |
80 | // MARK: - Ovveride
81 |
82 | open override var isHighlighted: Bool {
83 | didSet {
84 | UIView.animate(withDuration: 0.1, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
85 | self.alpha = self.isHighlighted ? NativeAppearance.actionable_element_highlight_opacity : 1
86 | }, completion: nil)
87 | }
88 | }
89 |
90 | // MARK: - Actions
91 |
92 | open func setVisible(_ state: Bool, animated: Bool) {
93 | let work = { [weak self] in
94 | guard let self = self else { return }
95 | self.alpha = state ? 1 : .zero
96 | }
97 | if animated {
98 | UIView.animate(withDuration: 0.45, delay: .zero, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .beginFromCurrentState], animations: {
99 | work()
100 | }, completion: nil)
101 | } else {
102 | work()
103 | }
104 | }
105 |
106 | // MARK: - Layout
107 |
108 | /**
109 | NativeUIKit: Layout wrapper. Native way for layout placeholder.
110 | */
111 | open func layout(y: CGFloat) {
112 | guard let superview = self.superview else { return }
113 | sizeToFit()
114 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
115 | frame.setWidth(width)
116 | setXCenter()
117 | frame.origin.y = y
118 | }
119 |
120 | /**
121 | NativeUIKit: Layout wrapper. Native way for layout placeholder.
122 | */
123 | open func layoutCenter() {
124 | guard let superview = self.superview else { return }
125 | let width = min(superview.readableWidth, NativeLayout.Sizes.actionable_area_maximum_width)
126 | setWidthAndFit(width: width)
127 | setXCenter()
128 | switch superview {
129 | case _ as UICollectionView:
130 | center.y = (superview.layoutHeight / 2) * 0.94
131 | case _ as UITableView:
132 | center.y = (superview.layoutHeight / 2) * 0.94
133 | default:
134 | center.y = (superview.frame.height / 2) * 0.94
135 | }
136 |
137 | }
138 |
139 | open override func layoutSubviews() {
140 | super.layoutSubviews()
141 | iconImageView.sizeToFit()
142 | iconImageView.setXCenter()
143 | iconImageView.frame.origin.y = layoutMargins.top
144 | headerLabel.layoutDynamicHeight(width: layoutWidth)
145 | headerLabel.frame.origin.y = iconImageView.frame.maxY + 12
146 | headerLabel.setXCenter()
147 | descriptionLabel.layoutDynamicHeight(width: layoutWidth)
148 | descriptionLabel.frame.origin.y = headerLabel.frame.maxY + 4
149 | descriptionLabel.setXCenter()
150 | }
151 |
152 | open override func sizeThatFits(_ size: CGSize) -> CGSize {
153 | layoutSubviews()
154 | return .init(width: size.width, height: descriptionLabel.frame.maxY + layoutMargins.bottom)
155 | }
156 | }
157 | #endif
158 |
--------------------------------------------------------------------------------
/Assets/Readme/Elements/NativeLargeActionButton.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------