Compare commits

...

184 Commits

Author SHA1 Message Date
Ivan Vorobei cbc46d4db4 Update to 1.6.6
Change layout system for arrow indicator. Now usage auto layout.
2019-06-19 07:41:18 +03:00
Ivan Vorobei 552f722a88 Update README.md 2019-06-18 17:54:16 +03:00
Ivan Vorobei 19caee5ccc Update README.md 2019-06-18 17:53:05 +03:00
Ivan Vorobei 2b5d20f26d Update README.md 2019-06-18 17:52:39 +03:00
Ivan Vorobei a6913a46a2 Add about Sheets 2019-06-18 17:51:41 +03:00
Ivan Vorobei fab0c7a274 Update README.md 2019-06-17 11:32:29 +03:00
Ivan Vorobei d04463f251 Update README.md 2019-06-17 11:13:26 +03:00
Ivan Vorobei d37aace4ec Update README.md 2019-06-17 11:11:48 +03:00
Ivan Vorobei 33d9b98d7d Update README.md 2019-06-17 11:10:46 +03:00
Ivan Vorobei 0363923e1b Update README.md 2019-06-17 11:09:37 +03:00
Ivan Vorobei 877108b08b Update README.md 2019-06-17 11:08:39 +03:00
Ivan Vorobei 7b25a6b878 Update README.md 2019-06-17 11:07:48 +03:00
Ivan Vorobei b69ae3ff7e Update README.md 2019-06-17 11:07:18 +03:00
Ivan Vorobei 4eac2276d4 Update README.md 2019-06-17 11:03:50 +03:00
Ivan Vorobei 38a6a10280 Update README.md 2019-06-17 11:02:12 +03:00
Ivan Vorobei aae897fc68 Update README.md 2019-06-17 11:00:27 +03:00
Ivan Vorobei 438811dbe5 Update README.md 2019-06-17 10:59:47 +03:00
Ivan Vorobei 7ea761b26e Update README.md 2019-06-16 23:20:30 +03:00
Ivan Vorobei 5c5457a09b Update README.md 2019-06-16 00:14:22 +03:00
Ivan Vorobei cdccba8929 Update README.md 2019-06-16 00:11:53 +03:00
Ivan Vorobei 196beb7592 Update README.md 2019-06-15 23:31:41 +03:00
Ivan Vorobei 91fe62e899 Update README.md 2019-06-15 23:30:40 +03:00
Ivan Vorobei bab71b560d Update README.md 2019-06-15 23:27:48 +03:00
Ivan Vorobei bb11bcd528 Add SPStorkSegue & icon for example 2019-06-15 23:25:30 +03:00
Ivan Vorobei d1f25b147f Update README.md 2019-06-15 14:25:50 +03:00
Ivan Vorobei 3eb459eab5 Update README.md 2019-06-15 14:22:50 +03:00
Ivan Vorobei 9060761733 Update README.md 2019-06-15 14:22:35 +03:00
Ivan Vorobei d7c5bd193c Update README.md 2019-06-15 14:20:16 +03:00
Ivan Vorobei 43a03de8d9 Update README.md 2019-06-15 14:19:46 +03:00
Ivan Vorobei 621bdb3e05 Update README.md 2019-06-15 14:19:18 +03:00
Ivan Vorobei d50ba88425 Update README.md 2019-06-15 14:19:00 +03:00
Ivan Vorobei 08b8422c26 Update README.md 2019-06-15 14:14:57 +03:00
Ivan Vorobei 9d13d508c6 Update scheme 2019-06-15 14:10:12 +03:00
Ivan Vorobei 6ae45f0568 Update README.md 2019-06-03 13:00:55 +03:00
Ivan Vorobei e5dbab65e1 Update README.md 2019-06-02 12:47:51 +03:00
Ivan Vorobei 07827b28a9 Update README.md 2019-06-02 12:21:24 +03:00
Ivan Vorobei 1dbd0ad54b Update README.md 2019-06-02 12:20:13 +03:00
Ivan Vorobei 49f2429633 Update README.md 2019-06-02 12:17:29 +03:00
Ivan Vorobei ef0a87e777 Update README.md 2019-06-02 11:59:53 +03:00
Ivan Vorobei b23a0b14e3 Update README.md 2019-06-02 11:57:05 +03:00
Ivan Vorobei a05b878af4 Update README.md 2019-06-02 11:56:40 +03:00
Ivan Vorobei 912c2d3903 Update README.md 2019-06-02 11:54:44 +03:00
Ivan Vorobei 3716912bc5 Update README.md 2019-06-02 11:53:51 +03:00
Ivan Vorobei ec9e174e14 Update README.md 2019-06-02 11:52:54 +03:00
Ivan Vorobei 6b98bf40c2 Update README.md 2019-06-02 11:51:51 +03:00
Ivan Vorobei 1167ca0a0d Update README.md 2019-06-02 11:50:46 +03:00
Ivan Vorobei c8c565d4ec Update README.md 2019-06-02 11:50:02 +03:00
Ivan Vorobei be0be7585b Update README.md 2019-06-02 11:46:52 +03:00
Ivan Vorobei c241629ea6 Update README.md 2019-06-02 11:44:35 +03:00
Ivan Vorobei 46afa63dbd Update README.md 2019-06-01 22:53:10 +03:00
Ivan Vorobei 682ab6127f Update README.md 2019-05-29 18:33:14 +03:00
Ivan Vorobei 4d70e9ca26 Update README.md 2019-05-29 18:31:56 +03:00
Ivan Vorobei 7091a625f3 Update README.md 2019-05-29 18:30:57 +03:00
Ivan Vorobei 5a83c3d1f3 Update README.md 2019-05-29 18:30:01 +03:00
Ivan Vorobei ad0c6eaf62 Update README.md 2019-05-25 15:34:29 +03:00
Ivan Vorobei 1f96f32980 Update README.md 2019-05-25 14:29:58 +03:00
Ivan Vorobei 03b38dfa0e Update README.md 2019-05-25 14:16:31 +03:00
Ivan Vorobei 2c35358336 Update README.md 2019-05-25 14:09:32 +03:00
Ivan Vorobei 18626df942 Update README.md 2019-05-25 14:09:13 +03:00
Ivan Vorobei 1a716980c0 Update README.md 2019-05-25 14:08:38 +03:00
Ivan Vorobei b5cf71046f Update FUNDING.yml 2019-05-24 22:00:23 +03:00
Ivan Vorobei 328d3739d6 Update README.md 2019-05-24 16:18:24 +03:00
Ivan Vorobei 2a858aa309 Update README.md 2019-05-24 16:17:33 +03:00
Ivan Vorobei f2937f6830 Update README.md 2019-05-24 12:57:20 +03:00
Ivan Vorobei c274892031 Update README.md 2019-05-24 12:57:03 +03:00
Ivan Vorobei 745968a053 Update README.md 2019-05-24 12:56:45 +03:00
Ivan Vorobei 4c90c708b7 Update README.md 2019-05-24 12:56:15 +03:00
Ivan Vorobei 871e96c1b9 Update README.md 2019-05-24 12:48:20 +03:00
Ivan Vorobei ad26638886 Update README.md 2019-05-24 12:48:01 +03:00
Ivan Vorobei 0306b46949 Update README.md 2019-05-24 12:47:34 +03:00
Ivan Vorobei 0f038463ed Update README.md 2019-05-24 12:46:56 +03:00
Ivan Vorobei ae01552b84 Update README.md 2019-05-24 12:46:37 +03:00
Ivan Vorobei 272bff5584 Update README.md 2019-05-24 12:45:50 +03:00
Ivan Vorobei 2adb5b4c88 Update README.md 2019-05-24 12:43:07 +03:00
Ivan Vorobei f930141a04 Update README.md 2019-05-24 12:42:50 +03:00
Ivan Vorobei 615fb4fcbc Update README.md 2019-05-24 12:42:15 +03:00
Ivan Vorobei 10dafb3853 Update README.md 2019-05-24 12:03:47 +03:00
Ivan Vorobei 7505c48033 Update README.md 2019-05-24 00:08:30 +03:00
Ivan Vorobei 35770b7362 Update README.md 2019-05-24 00:08:14 +03:00
Ivan Vorobei d478decba7 Update FUNDING.yml 2019-05-23 23:54:08 +03:00
Ivan Vorobei 51bb03327c Create FUNDING.yml 2019-05-23 23:27:59 +03:00
Ivan Vorobei f23eacf2ad Update README.md 2019-05-17 17:51:34 +03:00
Ivan Vorobei 04c9b77c75 Update README.md 2019-05-17 17:46:38 +03:00
Ivan Vorobei e7e83b5ad2 Update README.md 2019-05-17 17:46:01 +03:00
Ivan Vorobei 5911771ec9 Update README.md 2019-05-11 21:29:50 +03:00
Ivan Vorobei 6c1070848f Update README.md 2019-05-09 11:07:06 +03:00
Ivan Vorobei c18e8b8faf Update to 1.6.5
Fix bug with size `presentedView` when present other controller.
2019-05-08 18:14:35 +03:00
Ivan Vorobei 1d03424ab4 Update README.md 2019-05-08 11:20:34 +03:00
Ivan Vorobei 66556da572 Update README.md 2019-05-08 11:19:55 +03:00
Ivan Vorobei 6ebcfa59e9 Add Preview 2019-05-08 11:18:24 +03:00
Ivan Vorobei f6a2c31e2f Delete Preview.gif 2019-05-08 11:18:01 +03:00
Ivan Vorobei be3eb3f3a7 Update Preview 2019-05-08 11:16:57 +03:00
Ivan Vorobei a821389fee Update to 1.6.4
Update scale for parent controller. Update public method.
2019-05-07 13:43:50 +03:00
Ivan Vorobei e057aadaf1 Update public method 2019-05-07 13:43:05 +03:00
Ivan Vorobei 4c95e0ed3f Fix width
Reduce 1px of width parrent controller
2019-05-06 12:40:46 +03:00
Ivan Vorobei 71708b43c3 Update to 1.6.2
New width for parent controller.
2019-05-06 11:56:06 +03:00
Ivan Vorobei 66d7775d01 Update Example 2019-05-06 11:55:19 +03:00
Ivan Vorobei 298e0fdfc0 Update README.md 2019-05-05 18:04:59 +03:00
Ivan Vorobei 65070bce00 Update Example
And convert example project for swift 5 support.
2019-05-02 17:52:05 +03:00
Ivan Vorobei 2210afc7a7 Update README.md 2019-05-01 14:30:49 +03:00
Ivan Vorobei 94a8b06dde Update README.md 2019-04-30 20:58:58 +03:00
Ivan Vorobei 621e19cf78 Update README.md 2019-04-30 20:53:31 +03:00
Ivan Vorobei 6ae5e4f73d Update README.md 2019-04-30 16:31:35 +03:00
Ivan Vorobei 57d927bc49 Update README.md 2019-04-29 12:22:26 +03:00
Ivan Vorobei 1817c81bcc Update README.md 2019-04-29 12:20:49 +03:00
Ivan Vorobei 02e77c6074 Update README.md 2019-04-29 12:15:53 +03:00
Ivan Vorobei c922a8f522 Update README.md 2019-04-29 12:15:36 +03:00
Ivan Vorobei 86e7b3458d Update README.md 2019-04-29 12:15:00 +03:00
Ivan Vorobei a7ffa44434 Update README.md 2019-04-29 12:14:39 +03:00
Ivan Vorobei 96cc6b021a Update README.md 2019-04-29 12:14:16 +03:00
Ivan Vorobei 398da17b4a Update README.md 2019-04-28 23:05:55 +03:00
Ivan Vorobei 5e76f9f4d0 Update README.md 2019-04-28 18:52:54 +03:00
Ivan Vorobei a20a025a5b Update README.md 2019-04-28 18:47:39 +03:00
Ivan Vorobei 93e5b6f9de Update README.md 2019-04-28 18:46:27 +03:00
Ivan Vorobei 9d280b9b51 Update Readme 2019-04-28 16:28:53 +03:00
Ivan Vorobei 3d486c8f4b Update README.md 2019-04-26 18:39:12 +03:00
Ivan Vorobei d8fc226c9a Update README.md 2019-04-26 18:25:25 +03:00
Ivan Vorobei 7fd5eb41a6 Update Readme 2019-04-26 17:55:24 +03:00
Ivan Vorobei 263996e39d Update README.md 2019-04-26 17:53:52 +03:00
Ivan Vorobei b36cc7720d Update README.md 2019-04-26 17:53:38 +03:00
Ivan Vorobei f01ff0e904 Update Readme 2019-04-26 17:53:12 +03:00
Ivan Vorobei 92f29009c4 Update README.md 2019-04-26 17:45:06 +03:00
Ivan Vorobei b9813933b9 Update README.md 2019-04-26 17:36:54 +03:00
Ivan Vorobei ef0169a429 Update README.md 2019-04-26 17:35:52 +03:00
Ivan Vorobei 75766e6b7f Update README.md 2019-04-26 16:32:17 +03:00
Ivan Vorobei 9e8ed72013 Update README.md 2019-04-26 16:31:16 +03:00
Ivan Vorobei 29d6f3af93 Update README.md 2019-04-26 16:30:27 +03:00
Ivan Vorobei afa7e48e4c Update README.md 2019-04-26 16:20:25 +03:00
Ivan Vorobei b4c022e889 Update README.md 2019-04-26 16:13:36 +03:00
Ivan Vorobei 3c6e7e2c9c Update README.md 2019-04-26 15:55:05 +03:00
Ivan Vorobei 16e4685963 Update README.md 2019-04-26 15:53:29 +03:00
Ivan Vorobei e8e0e22259 Update README.md 2019-04-26 15:51:27 +03:00
Ivan Vorobei 19551282e6 Update Readme 2019-04-26 15:47:35 +03:00
Ivan Vorobei bc66345c6a Update Readme 2019-04-26 15:43:30 +03:00
Ivan Vorobei 73152ed8df Update README.md 2019-04-26 15:33:07 +03:00
Ivan Vorobei 431e9f58d5 Update README.md 2019-04-26 15:30:26 +03:00
Ivan Vorobei c3d75dac5e Update README.md 2019-04-26 15:30:01 +03:00
Ivan Vorobei cf9e7501d2 Update README.md 2019-04-26 15:27:47 +03:00
Ivan Vorobei 182ee5f0f0 Update README.md 2019-04-26 15:26:31 +03:00
Ivan Vorobei b2b37e717c Update README.md 2019-04-26 15:25:21 +03:00
Ivan Vorobei c0ea9d29a1 Update README.md 2019-04-26 15:21:57 +03:00
Ivan Vorobei cb55b4861a Update README.md 2019-04-26 15:20:57 +03:00
Ivan Vorobei 6a0aa725f7 Update README.md 2019-04-26 15:19:27 +03:00
Ivan Vorobei aebe62a9f2 Update README.md 2019-04-26 15:18:28 +03:00
Ivan Vorobei a0c0bf6885 Update README.md 2019-04-26 15:12:32 +03:00
Ivan Vorobei c0be873778 Update README.md 2019-04-26 15:11:04 +03:00
Ivan Vorobei 7fa550f79c Update README.md 2019-04-26 14:40:39 +03:00
Ivan Vorobei 6a22bb178b Update README.md 2019-04-25 16:57:19 +03:00
Ivan Vorobei 8993c2011d Update README.md 2019-04-24 12:03:09 +03:00
Ivan Vorobei 70199b65ee Update README.md 2019-04-23 12:40:06 +03:00
Ivan Vorobei 99ed2e84e1 Update README.md 2019-04-23 12:38:20 +03:00
Ivan Vorobei 6d8bf7c70a Update README.md 2019-04-23 12:26:31 +03:00
Ivan Vorobei a21dd49806 Update README.md 2019-04-23 12:05:22 +03:00
Ivan Vorobei 2cb195fcab Update README.md 2019-04-23 12:04:12 +03:00
Ivan Vorobei 4c78642040 Update README.md 2019-04-23 12:03:21 +03:00
Ivan Vorobei 73d297de19 Update README.md 2019-04-22 09:20:34 +03:00
Ivan Vorobei 1d167c9506 Update README.md 2019-04-22 09:19:19 +03:00
Ivan Vorobei 0b07e8e2cb Update README.md 2019-04-17 16:19:43 +03:00
Ivan Vorobei 8500571554 Update README.md 2019-04-17 16:11:08 +03:00
Ivan Vorobei 13134f2748 Update README.md 2019-04-17 16:05:39 +03:00
Ivan Vorobei 6e1a5c85b3 Update README.md 2019-04-17 16:04:01 +03:00
Ivan Vorobei eab9045cb5 Update README.md 2019-04-17 16:03:25 +03:00
Ivan Vorobei f567582b4d Update README.md 2019-04-17 16:00:48 +03:00
Ivan Vorobei 30365fde24 Fix protect level
Fix bug with `topScrollIndicatorInset` property, set `public` protect level. Add support in `podspec` swift `4.2` & `5.0`.
2019-04-17 00:49:40 +03:00
Ivan Vorobei 6b8fa51706 Update to 1.6.1
Add haptic feedback for some moments: see `hapticMoments`. Update example and Readme. Add support Carthage. Fix bug with func `removeAllAnimation` for `IndicatorView`.
2019-04-12 14:05:27 +03:00
Ivan Vorobei 1f1aa2ea8d Fix edit action
If translation < -50, indicator now force hide. Fix bug with edit actions for table view: implement `gestureRecognizerShouldBegin`.
2019-04-08 11:09:18 +03:00
Ivan Vorobei 914ce0f689 Fix bug with gester and EditingStyle for TableView
Implement `gestureRecognizerShouldBegin` func.
2019-04-05 23:40:00 +03:00
Ivan Vorobei 5dfab81504 Update SPStorkController.podspec 2019-04-04 14:10:29 +03:00
Ivan Vorobei 9270185bf6 Update SPStorkController.podspec 2019-04-04 14:06:45 +03:00
Ivan Vorobei 43bc6c27ee Update SPStorkController.podspec 2019-03-26 14:51:25 +03:00
Ivan Vorobei 551ccf3bf1 Update SPStorkController.podspec 2019-03-26 14:40:17 +03:00
Ivan Vorobei 0488521869 Update SPStorkController.podspec 2019-03-26 14:32:46 +03:00
Ivan Vorobei 9eae918f9d Update SPStorkController.podspec 2019-03-26 14:32:13 +03:00
Ivan Vorobei 28ed6b6ebc Update SPStorkController.podspec 2019-03-26 14:30:08 +03:00
Ivan Vorobei b783329b69 Update SPStorkController.podspec 2019-03-26 14:26:36 +03:00
Ivan Vorobei 84256152dc Update to 1.6
Update duration animation for show / hide indicator view when scrolling.
2019-03-26 14:19:27 +03:00
Ivan Vorobei ac366c84fd Update to 1.5.8 2019-03-25 23:30:30 +03:00
Ivan Vorobei 64bebe0645 Update to 1.5.7
Add `closeButton` and parametres.
2019-03-25 15:42:10 +03:00
Ivan Vorobei 1efa55aefb Update to 1.5.6
Add events delegate
2019-03-24 18:57:27 +03:00
Ivan Vorobei e5371ca20c Update to 1.5.5
Add new parameter `hideIndicatorWhenScroll` - it allow shows and hide indicator when scrolling. Also fixed bug when invalid frame for dismissing action.
2019-03-24 13:23:08 +03:00
Ivan Vorobei fdbc1e3527 Update README.md 2019-03-23 23:28:22 +03:00
Ivan Vorobei 306547671c Update README.md 2019-03-23 19:46:22 +03:00
Ivan Vorobei 1fede9eb64 Update to 1.5.4
Fix bug with dublicate indicator
2019-03-07 11:34:01 +03:00
Ivan Vorobei 3ef2ff81bc Update README.md 2019-03-04 15:34:07 +03:00
180 changed files with 3396 additions and 1360 deletions
+8
View File
@@ -0,0 +1,8 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: ivanvorobei
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: # https://xcode-shop.com
+37
View File
@@ -1 +1,38 @@
# Mac OS X
.DS_Store
# Xcode
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
.build/
# Carthage
Carthage/Build
File diff suppressed because it is too large Load Diff
@@ -1,93 +1,111 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon_20pt@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon_20pt@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon_29pt@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon_29pt@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon_40pt@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon_40pt@3x.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon_60pt@2x.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon_60pt@3x.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon_20pt.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon_20pt@2x-1.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon_29pt.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon_29pt@2x-1.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon_40pt.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon_40pt@2x-1.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon_76pt.png",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon_76pt@2x.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon_83.5@2x.png",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon.png",
"scale" : "1x"
}
],
Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,30 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
public enum SPFakeBarNavigationStyle {
case large
case small
case stork
case noContent
}
@@ -21,9 +21,9 @@
import UIKit
public class SPFakeBarView: UIView {
open class SPFakeBarView: UIView {
public var style: SPNavigationTitleStyle = .small {
public var style: SPFakeBarNavigationStyle = .small {
didSet {
self.updateStyle()
}
@@ -32,7 +32,7 @@ public class SPFakeBarView: UIView {
private var settedHeight: CGFloat = 0
public var height: CGFloat {
get {
return (self.settedHeight) + (self.addStatusBarHeight ? UIViewController.statusBarHeight : 0)
return (self.settedHeight) + (self.addStatusBarHeight ? UIApplication.shared.statusBarFrame.height : 0)
}
set {
self.settedHeight = newValue
@@ -47,22 +47,24 @@ public class SPFakeBarView: UIView {
}
}
public var elementsColor: UIColor = UINavigationController.elementsColor {
public var elementsColor: UIColor = SPFakeBarView.navigationElementsColor {
didSet {
self.leftButton.setTitleColor(self.elementsColor)
self.rightButton.setTitleColor(self.elementsColor)
self.leftButton.setTitleColor(self.elementsColor, for: .normal)
self.leftButton.setTitleColor(self.elementsColor.withAlphaComponent(0.7), for: .highlighted)
self.rightButton.setTitleColor(self.elementsColor, for: .normal)
self.rightButton.setTitleColor(self.elementsColor.withAlphaComponent(0.7), for: .highlighted)
}
}
public var closeButtonPossition: CloseButtonPosition = .none {
didSet {
self.leftButton.titleLabel?.font = UIFont.system(weight: .regular, size: 17)
self.rightButton.titleLabel?.font = UIFont.system(weight: .regular, size: 17)
self.leftButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .regular)
self.rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .regular)
switch self.closeButtonPossition {
case .left:
self.leftButton.titleLabel?.font = UIFont.system(weight: .demiBold, size: 17)
self.leftButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
case .right:
self.rightButton.titleLabel?.font = UIFont.system(weight: .demiBold, size: 17)
self.rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
case .none:
break
}
@@ -74,21 +76,25 @@ public class SPFakeBarView: UIView {
public var leftButton = UIButton.init()
public var rightButton = UIButton.init()
public let separatorView = UIView()
public let blurView: UIVisualEffectView = {
let effect = UIBlurEffect(style: .extraLight)
return UIVisualEffectView.init(effect: effect)
}()
private var titleBottomConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
private var topConstraint: NSLayoutConstraint?
private var leadingConstraint: NSLayoutConstraint?
private var trailingConstraint: NSLayoutConstraint?
private let blurView = UIVisualEffectView.init(style: .extraLight)
private let separatorView = UIView()
public init(style: SPNavigationTitleStyle) {
public init(style: SPFakeBarNavigationStyle) {
super.init(frame: CGRect.zero)
self.style = style
self.commonInit()
}
public required init?(coder aDecoder: NSCoder) {
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.style = .small
self.commonInit()
@@ -105,7 +111,7 @@ public class SPFakeBarView: UIView {
self.blurView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
self.addSubview(self.separatorView)
self.separatorView.backgroundColor = UIColor.init(hex: "BFBFBF")
self.separatorView.backgroundColor = UIColor.init(red: 191 / 255.0, green: 191 / 255.0, blue: 191 / 255.0, alpha: 1)
self.separatorView.translatesAutoresizingMaskIntoConstraints = false
self.separatorView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
self.separatorView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
@@ -120,25 +126,27 @@ public class SPFakeBarView: UIView {
self.titleBottomConstraint?.isActive = true
self.addSubview(self.subtitleLabel)
self.subtitleLabel.textColor = UIColor.init(hex: "8E8E92")
self.subtitleLabel.font = UIFont.system(weight: .demiBold, size: 13)
self.subtitleLabel.textColor = UIColor.init(red: 142 / 255.0, green: 142 / 255.0, blue: 146 / 255.0, alpha: 1)
self.subtitleLabel.font = UIFont.systemFont(ofSize: 13, weight: .semibold)
self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
self.subtitleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 16).isActive = true
self.subtitleLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -16).isActive = true
self.subtitleLabel.bottomAnchor.constraint(equalTo: self.titleLabel.topAnchor, constant: 0).isActive = true
self.leftButton.setTitleColor(self.elementsColor)
self.leftButton.setTitleColor(self.elementsColor, for: .normal)
self.leftButton.setTitleColor(self.elementsColor.withAlphaComponent(0.7), for: .highlighted)
self.leftButton.titleLabel?.textAlignment = .left
self.leftButton.titleLabel?.font = UIFont.system(weight: .demiBold, size: 16)
self.leftButton.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
self.leftButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 17, bottom: 0, right: 0)
self.addSubview(self.leftButton)
self.leftButton.translatesAutoresizingMaskIntoConstraints = false
self.leftButton.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
self.leftButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -12).isActive = true
self.rightButton.setTitleColor(self.elementsColor)
self.rightButton.setTitleColor(self.elementsColor, for: .normal)
self.rightButton.setTitleColor(self.elementsColor.withAlphaComponent(0.7), for: .highlighted)
self.rightButton.titleLabel?.textAlignment = .right
self.rightButton.titleLabel?.font = UIFont.system(weight: .demiBold, size: 17)
self.rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
self.rightButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16)
self.addSubview(self.rightButton)
self.rightButton.translatesAutoresizingMaskIntoConstraints = false
@@ -151,7 +159,7 @@ public class SPFakeBarView: UIView {
self.updateStyle()
}
public override func layoutSubviews() {
override open func layoutSubviews() {
super.layoutSubviews()
self.setContraints()
}
@@ -177,7 +185,7 @@ public class SPFakeBarView: UIView {
private func updateStyle() {
switch self.style {
case .small:
if UIViewController.statusBarHeight == 44 {
if UIApplication.shared.statusBarFrame.height == 44 {
self.height = 88 - 44
self.titleBottomConstraint?.constant = -12
} else {
@@ -185,26 +193,29 @@ public class SPFakeBarView: UIView {
self.titleBottomConstraint?.constant = -12
}
self.addStatusBarHeight = true
self.titleLabel.font = UIFont.system(weight: .demiBold, size: 17)
self.titleLabel.setCenterAlignment()
self.titleLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
self.titleLabel.textAlignment = .center
case .stork:
self.height = 66
self.titleBottomConstraint?.constant = -12
self.addStatusBarHeight = false
self.titleLabel.font = UIFont.system(weight: .demiBold, size: 17)
self.titleLabel.setCenterAlignment()
self.titleLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
self.titleLabel.textAlignment = .center
case .large:
if UIViewController.statusBarHeight == 44 {
if UIApplication.shared.statusBarFrame.height == 44 {
self.height = 140 - 44
self.titleBottomConstraint?.constant = -8
} else {
self.height = 112 - 20
self.height = 116 - 20
self.titleBottomConstraint?.constant = -4
}
self.addStatusBarHeight = true
self.titleLabel.font = UIFont.system(weight: .bold, size: 34)
self.titleLabel.font = UIFont.systemFont(ofSize: 34, weight: .bold)
self.titleLabel.textAlignment = .left
break
case .noContent:
self.height = 0
self.addStatusBarHeight = true
}
self.updateConstraints()
@@ -222,3 +233,18 @@ public class SPFakeBarView: UIView {
}
}
extension SPFakeBarView {
static var navigationElementsColor: UIColor {
get {
if UINavigationBar.appearance().tintColor != nil {
return UINavigationBar.appearance().tintColor
} else {
return UIColor.init(red: 0 / 255.0, green: 122 / 255.0, blue: 255 / 255.0, alpha: 1)
}
}
set {
UINavigationBar.appearance().tintColor = newValue
}
}
}
@@ -0,0 +1,88 @@
import UIKit
class SPStorkCodeDraw : NSObject {
private struct Cache {
static let gradient: CGGradient = CGGradient(colorsSpace: nil, colors: [UIColor.red.cgColor, UIColor.red.cgColor] as CFArray, locations: [0, 1])!
}
@objc dynamic class var gradient: CGGradient { return Cache.gradient }
@objc dynamic class func drawClose(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 100, height: 100), target: targetFrame)
context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY)
context.scaleBy(x: resizedFrame.width / 100, y: resizedFrame.height / 100)
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 92.02, y: 22.92))
bezierPath.addLine(to: CGPoint(x: 64.42, y: 50.52))
bezierPath.addLine(to: CGPoint(x: 92.02, y: 78.13))
bezierPath.addCurve(to: CGPoint(x: 92.02, y: 92.99), controlPoint1: CGPoint(x: 96.13, y: 82.23), controlPoint2: CGPoint(x: 96.13, y: 88.89))
bezierPath.addCurve(to: CGPoint(x: 84.59, y: 96.07), controlPoint1: CGPoint(x: 89.97, y: 95.05), controlPoint2: CGPoint(x: 87.28, y: 96.07))
bezierPath.addCurve(to: CGPoint(x: 77.16, y: 92.99), controlPoint1: CGPoint(x: 81.9, y: 96.07), controlPoint2: CGPoint(x: 79.22, y: 95.05))
bezierPath.addLine(to: CGPoint(x: 49.55, y: 65.38))
bezierPath.addLine(to: CGPoint(x: 21.95, y: 92.99))
bezierPath.addCurve(to: CGPoint(x: 14.51, y: 96.07), controlPoint1: CGPoint(x: 19.89, y: 95.05), controlPoint2: CGPoint(x: 17.2, y: 96.07))
bezierPath.addCurve(to: CGPoint(x: 7.08, y: 92.99), controlPoint1: CGPoint(x: 11.82, y: 96.07), controlPoint2: CGPoint(x: 9.13, y: 95.05))
bezierPath.addCurve(to: CGPoint(x: 7.08, y: 78.13), controlPoint1: CGPoint(x: 2.97, y: 88.89), controlPoint2: CGPoint(x: 2.97, y: 82.23))
bezierPath.addLine(to: CGPoint(x: 34.69, y: 50.52))
bezierPath.addLine(to: CGPoint(x: 7.08, y: 22.92))
bezierPath.addCurve(to: CGPoint(x: 7.08, y: 8.04), controlPoint1: CGPoint(x: 2.97, y: 18.8), controlPoint2: CGPoint(x: 2.97, y: 12.15))
bezierPath.addCurve(to: CGPoint(x: 21.94, y: 8.04), controlPoint1: CGPoint(x: 11.18, y: 3.94), controlPoint2: CGPoint(x: 17.84, y: 3.94))
bezierPath.addLine(to: CGPoint(x: 49.55, y: 35.65))
bezierPath.addLine(to: CGPoint(x: 77.16, y: 8.04))
bezierPath.addCurve(to: CGPoint(x: 92.02, y: 8.04), controlPoint1: CGPoint(x: 81.26, y: 3.94), controlPoint2: CGPoint(x: 87.92, y: 3.94))
bezierPath.addCurve(to: CGPoint(x: 92.02, y: 22.92), controlPoint1: CGPoint(x: 96.13, y: 12.15), controlPoint2: CGPoint(x: 96.13, y: 18.8))
bezierPath.close()
color.setFill()
bezierPath.fill()
context.restoreGState()
}
@objc(StyleKitNameResizingBehavior)
enum ResizingBehavior: Int {
case aspectFit
case aspectFill
case stretch
case center
func apply(rect: CGRect, target: CGRect) -> CGRect {
if rect == target || target == CGRect.zero {
return rect
}
var scales = CGSize.zero
scales.width = abs(target.width / rect.width)
scales.height = abs(target.height / rect.height)
switch self {
case .aspectFit:
scales.width = min(scales.width, scales.height)
scales.height = scales.width
case .aspectFill:
scales.width = max(scales.width, scales.height)
scales.height = scales.width
case .stretch:
break
case .center:
scales.width = 1
scales.height = 1
}
var result = rect.standardized
result.size.width *= scales.width
result.size.height *= scales.height
result.origin.x = target.minX + (target.width - result.width) / 2
result.origin.y = target.minY + (target.height - result.height) / 2
return result
}
}
private override init() {}
}
@@ -29,9 +29,19 @@ extension UIViewController {
&& presentingViewController != nil
}
public func presentAsStork(_ controller: UIViewController, height: CGFloat? = nil, showIndicator: Bool = false, complection: (() -> Void)? = nil) {
public func presentAsStork(_ controller: UIViewController, height: CGFloat? = nil) {
let transitionDelegate = SPStorkTransitioningDelegate()
transitionDelegate.customHeight = height
controller.transitioningDelegate = transitionDelegate
controller.modalPresentationStyle = .custom
controller.modalPresentationCapturesStatusBarAppearance = true
self.present(controller, animated: true, completion: nil)
}
public func presentAsStork(_ controller: UIViewController, height: CGFloat?, showIndicator: Bool, showCloseButton: Bool, complection: (() -> Void)? = nil) {
let transitionDelegate = SPStorkTransitioningDelegate()
transitionDelegate.customHeight = height
transitionDelegate.showCloseButton = showCloseButton
transitionDelegate.showIndicator = showIndicator
controller.transitioningDelegate = transitionDelegate
controller.modalPresentationStyle = .custom
@@ -0,0 +1,29 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
public enum SPStorkHapticMoments {
case willPresent
case willDismiss
case willDismissIfRelease
}
@@ -0,0 +1,29 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
@objc public protocol SPStorkControllerDelegate: class {
@objc optional func didDismissStorkBySwipe()
@objc optional func didDismissStorkByTap()
}
@@ -21,7 +21,7 @@
import UIKit
public struct SPStorkController {
public enum SPStorkController {
static public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let controller = self.controller(for: scrollView) {
@@ -35,7 +35,9 @@ public struct SPStorkController {
presentationController.setIndicator(style: scrollView.isTracking ? .line : .arrow)
if translation >= presentationController.translateForDismiss * 0.4 {
if !scrollView.isTracking && !scrollView.isDragging {
presentationController.presentedViewController.dismiss(animated: true, completion: nil)
presentationController.presentedViewController.dismiss(animated: true, completion: {
presentationController.storkDelegate?.didDismissStorkBySwipe?()
})
return
}
}
@@ -46,11 +48,17 @@ public struct SPStorkController {
presentationController.setIndicator(style: .arrow)
presentationController.scrollViewDidScroll(0)
}
if translation < -5 {
presentationController.setIndicator(visible: false, forse: (translation < -50))
} else {
presentationController.setIndicator(visible: true, forse: false)
}
}
}
}
static var topScrollIndicatorInset: CGFloat {
static public var topScrollIndicatorInset: CGFloat {
return 6
}
@@ -73,6 +81,4 @@ public struct SPStorkController {
}
return nextResponder as? UIViewController
}
private init() {}
}
@@ -0,0 +1,34 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
public class SPStorkSegue: UIStoryboardSegue {
public var transitioningDelegate: SPStorkTransitioningDelegate?
override public func perform() {
transitioningDelegate = transitioningDelegate ?? SPStorkTransitioningDelegate()
destination.transitioningDelegate = transitioningDelegate
destination.modalPresentationStyle = .custom
super.perform()
}
}
@@ -29,8 +29,10 @@ final class SPStorkDismissingAnimationController: NSObject, UIViewControllerAnim
return
}
let finalFrameForPresentedView = transitionContext.finalFrame(for: presentedViewController)
let containerView = transitionContext.containerView
let offscreenFrame = CGRect(x: 0, y: containerView.bounds.height, width: containerView.bounds.width, height: containerView.bounds.height)
let offscreenFrame = CGRect(x: 0, y: containerView.bounds.height, width: finalFrameForPresentedView.width, height: finalFrameForPresentedView.height)
UIView.animate(
withDuration: transitionDuration(using: transitionContext),
@@ -25,16 +25,21 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
var swipeToDismissEnabled: Bool = true
var tapAroundToDismissEnabled: Bool = true
var showCloseButton: Bool = false
var showIndicator: Bool = true
var indicatorColor: UIColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
var hideIndicatorWhenScroll: Bool = false
var customHeight: CGFloat? = nil
var translateForDismiss: CGFloat = 200
var hapticMoments: [SPStorkHapticMoments] = [.willDismissIfRelease]
var transitioningDelegate: SPStorkTransitioningDelegate?
weak var storkDelegate: SPStorkControllerDelegate?
var pan: UIPanGestureRecognizer?
var tap: UITapGestureRecognizer?
private var closeButton = SPStorkCloseButton()
private var indicatorView = SPStorkIndicatorView()
private var gradeView: UIView = UIView()
private let snapshotViewContainer = UIView()
@@ -47,6 +52,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
private var workGester: Bool = false
private var startDismissing: Bool = false
private var afterReleaseDismissing: Bool = false
private var topSpace: CGFloat {
let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.height
@@ -58,26 +64,43 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
private var scaleForPresentingView: CGFloat {
guard let containerView = containerView else { return 0 }
let factor = 1 - (self.topSpace * 2 / containerView.frame.height)
let factor = 1 - ((self.cornerRadius + 3) * 2 / containerView.frame.width)
return factor
}
private var feedbackGenerator: UIImpactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
override var presentedView: UIView? {
let view = self.presentedViewController.view
if view?.frame.origin == CGPoint.zero {
view?.frame = self.frameOfPresentedViewInContainerView
}
return view
}
override var frameOfPresentedViewInContainerView: CGRect {
guard let containerView = containerView else { return .zero }
let baseY: CGFloat = self.topSpace + 13
let maxHeight: CGFloat = containerView.bounds.height - baseY
var height: CGFloat = maxHeight
var customHeight = self.customHeight ?? containerView.bounds.height
if customHeight > containerView.bounds.height {
customHeight = containerView.bounds.height
print("SPStorkController - Custom height change to default value. Your height more maximum value")
if let customHeight = self.customHeight {
if customHeight < maxHeight {
height = customHeight
} else {
print("SPStorkController - Custom height change to default value. Your height more maximum value")
}
}
let additionTranslate = containerView.bounds.height - customHeight
let yOffset: CGFloat = self.topSpace + 13 + additionTranslate
return CGRect(x: 0, y: yOffset, width: containerView.bounds.width, height: containerView.bounds.height - yOffset)
return CGRect(x: 0, y: containerView.bounds.height - height, width: containerView.bounds.width, height: height)
}
override func presentationTransitionWillBegin() {
super.presentationTransitionWillBegin()
if !self.hapticMoments.isEmpty {
self.feedbackGenerator.prepare()
}
guard let containerView = self.containerView, let presentedView = self.presentedView, let window = containerView.window else { return }
if self.showIndicator {
@@ -86,11 +109,22 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
tap.cancelsTouchesInView = false
self.indicatorView.addGestureRecognizer(tap)
presentedView.addSubview(self.indicatorView)
self.indicatorView.translatesAutoresizingMaskIntoConstraints = false
self.indicatorView.widthAnchor.constraint(equalToConstant: 36).isActive = true
self.indicatorView.heightAnchor.constraint(equalToConstant: 13).isActive = true
self.indicatorView.centerXAnchor.constraint(equalTo: presentedView.centerXAnchor).isActive = true
self.indicatorView.topAnchor.constraint(equalTo: presentedView.topAnchor, constant: 12).isActive = true
}
self.updateLayoutIndicator()
self.indicatorView.style = .arrow
self.gradeView.alpha = 0
if self.showCloseButton {
self.closeButton.addTarget(self, action: #selector(self.dismissAction), for: .touchUpInside)
presentedView.addSubview(self.closeButton)
}
self.updateLayoutCloseButton()
let initialFrame: CGRect = presentingViewController.isPresentedAsStork ? presentingViewController.view.frame : containerView.bounds
containerView.insertSubview(self.snapshotViewContainer, belowSubview: presentedViewController.view)
@@ -156,6 +190,10 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
rootSnapshotView?.removeFromSuperview()
rootSnapshotRoundedView?.removeFromSuperview()
})
if self.hapticMoments.contains(.willPresent) {
self.feedbackGenerator.impactOccurred()
}
}
override func presentationTransitionDidEnd(_ completed: Bool) {
@@ -186,7 +224,9 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
@objc func dismissAction() {
self.presentingViewController.view.endEditing(true)
self.presentedViewController.view.endEditing(true)
self.presentedViewController.dismiss(animated: true, completion: nil)
self.presentedViewController.dismiss(animated: true, completion: {
self.storkDelegate?.didDismissStorkByTap?()
})
}
override func dismissalTransitionWillBegin() {
@@ -245,6 +285,9 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
self.snapshotView?.transform = .identity
self.snapshotViewContainer.transform = finalTransform
self.gradeView.alpha = 0
if self.hapticMoments.contains(.willDismiss) {
self.feedbackGenerator.impactOccurred()
}
}, completion: { _ in
rootSnapshotView?.removeFromSuperview()
rootSnapshotRoundedView?.removeFromSuperview()
@@ -258,6 +301,8 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
self.backgroundView.removeFromSuperview()
self.snapshotView?.removeFromSuperview()
self.snapshotViewContainer.removeFromSuperview()
self.indicatorView.removeFromSuperview()
self.closeButton.removeFromSuperview()
let offscreenFrame = CGRect(x: 0, y: containerView.bounds.height, width: containerView.bounds.width, height: containerView.bounds.height)
presentedViewController.view.frame = offscreenFrame
@@ -280,8 +325,8 @@ extension SPStorkPresentationController {
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: containerView)
case .changed:
self.workGester = true
let translation = gestureRecognizer.translation(in: presentedView)
if self.swipeToDismissEnabled {
let translation = gestureRecognizer.translation(in: presentedView)
self.updatePresentedViewForTranslation(inVerticalDirection: translation.y)
} else {
gestureRecognizer.setTranslation(.zero, in: presentedView)
@@ -290,7 +335,9 @@ extension SPStorkPresentationController {
self.workGester = false
let translation = gestureRecognizer.translation(in: presentedView).y
if translation >= self.translateForDismiss {
self.presentedViewController.dismiss(animated: true, completion: nil)
self.presentedViewController.dismiss(animated: true, completion: {
self.storkDelegate?.didDismissStorkBySwipe?()
})
} else {
self.indicatorView.style = .arrow
UIView.animate(
@@ -310,6 +357,14 @@ extension SPStorkPresentationController {
}
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let gester = gestureRecognizer as? UIPanGestureRecognizer {
let velocity = gester.velocity(in: self.presentedViewController.view)
return abs(velocity.y) > abs(velocity.x)
}
return true
}
func scrollViewDidScroll(_ translation: CGFloat) {
if !self.workGester {
self.updatePresentedViewForTranslation(inVerticalDirection: translation)
@@ -325,6 +380,22 @@ extension SPStorkPresentationController {
self.indicatorView.style = style
}
func setIndicator(visible: Bool, forse: Bool) {
guard self.hideIndicatorWhenScroll else { return }
let newAlpha: CGFloat = visible ? 1 : 0
if forse {
self.indicatorView.layer.removeAllAnimations()
self.indicatorView.alpha = newAlpha
return
}
if self.indicatorView.alpha == newAlpha {
return
}
UIView.animate(withDuration: 0.18, animations: {
self.indicatorView.alpha = newAlpha
})
}
private func updatePresentedViewForTranslation(inVerticalDirection translation: CGFloat) {
if self.startDismissing { return }
@@ -351,6 +422,16 @@ extension SPStorkPresentationController {
} else {
self.presentedView?.transform = CGAffineTransform.identity
}
if self.swipeToDismissEnabled {
let afterRealseDismissing = (translation >= self.translateForDismiss)
if afterRealseDismissing != self.afterReleaseDismissing {
self.afterReleaseDismissing = afterRealseDismissing
if self.hapticMoments.contains(.willDismissIfRelease) {
self.feedbackGenerator.impactOccurred()
}
}
}
}
}
@@ -361,10 +442,7 @@ extension SPStorkPresentationController {
guard let containerView = containerView else { return }
self.updateSnapshotAspectRatio()
if presentedViewController.view.isDescendant(of: containerView) {
UIView.animate(withDuration: 0.1) { [weak self] in
guard let `self` = self else { return }
self.presentedViewController.view.frame = self.frameOfPresentedViewInContainerView
}
self.presentedViewController.view.frame = self.frameOfPresentedViewInContainerView
}
}
@@ -372,6 +450,7 @@ extension SPStorkPresentationController {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { contex in
self.updateLayoutIndicator()
self.updateLayoutCloseButton()
}, completion: { [weak self] _ in
self?.updateSnapshotAspectRatio()
self?.updateSnapshot()
@@ -379,11 +458,16 @@ extension SPStorkPresentationController {
}
private func updateLayoutIndicator() {
guard let presentedView = self.presentedView else { return }
self.indicatorView.style = .line
self.indicatorView.sizeToFit()
self.indicatorView.frame.origin.y = 12
self.indicatorView.center.x = presentedView.frame.width / 2
//self.indicatorView.frame.origin.y = 12
//self.indicatorView.center.x = presentedView.frame.width / 2
}
private func updateLayoutCloseButton() {
guard let presentedView = self.presentedView else { return }
self.closeButton.sizeToFit()
self.closeButton.layout(bottomX: presentedView.frame.width - 19, y: 19)
}
private func updateSnapshot() {
@@ -25,22 +25,30 @@ public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTrans
public var swipeToDismissEnabled: Bool = true
public var tapAroundToDismissEnabled: Bool = true
public var showCloseButton: Bool = false
public var showIndicator: Bool = true
public var indicatorColor: UIColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
public var hideIndicatorWhenScroll: Bool = false
public var customHeight: CGFloat? = nil
public var translateForDismiss: CGFloat = 200
public var cornerRadius: CGFloat = 10
public var hapticMoments: [SPStorkHapticMoments] = [.willDismissIfRelease]
public weak var storkDelegate: SPStorkControllerDelegate? = nil
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let controller = SPStorkPresentationController(presentedViewController: presented, presenting: presenting)
controller.swipeToDismissEnabled = self.swipeToDismissEnabled
controller.tapAroundToDismissEnabled = self.tapAroundToDismissEnabled
controller.showCloseButton = self.showCloseButton
controller.showIndicator = self.showIndicator
controller.indicatorColor = self.indicatorColor
controller.hideIndicatorWhenScroll = self.hideIndicatorWhenScroll
controller.customHeight = self.customHeight
controller.translateForDismiss = self.translateForDismiss
controller.cornerRadius = self.cornerRadius
controller.hapticMoments = self.hapticMoments
controller.transitioningDelegate = self
controller.storkDelegate = self.storkDelegate
return controller
}
@@ -0,0 +1,78 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
open class SPStorkCloseButton: UIButton {
let iconView = SPStorkCloseView()
var widthIconFactor: CGFloat = 1
var heightIconFactor: CGFloat = 1
var color = UIColor.blue {
didSet {
self.iconView.color = self.color
}
}
override open var isHighlighted: Bool {
didSet {
self.iconView.color = self.color.withAlphaComponent(self.isHighlighted ? 0.7 : 1)
}
}
init() {
super.init(frame: .zero)
self.commonInit()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func commonInit() {
self.iconView.isUserInteractionEnabled = false
self.addSubview(self.iconView)
self.backgroundColor = UIColor.init(red: 239 / 255.0, green: 239 / 255.0, blue: 244 / 255.0, alpha: 1)
self.color = UIColor.init(red: 142 / 255.0, green: 142 / 255.0, blue: 147 / 255.0, alpha: 1)
self.widthIconFactor = 0.36
self.heightIconFactor = 0.36
}
func layout(bottomX: CGFloat, y: CGFloat) {
self.sizeToFit()
self.frame.origin.x = bottomX - self.frame.width
self.frame.origin.y = y
}
override open func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.width / 2
self.iconView.frame = CGRect.init(x: 0, y: 0, width: self.frame.width * self.widthIconFactor, height: self.frame.height * self.heightIconFactor)
self.iconView.center = CGPoint.init(x: self.frame.width / 2, y: self.frame.height / 2)
}
override open func sizeToFit() {
super.sizeToFit()
self.frame = CGRect.init(x: self.frame.origin.x, y: self.frame.origin.y, width: 30, height: 30)
}
}
@@ -0,0 +1,50 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
open class SPStorkCloseView: UIView {
var color = UIColor.blue {
didSet {
self.setNeedsDisplay()
}
}
init() {
super.init(frame: CGRect.zero)
self.commonInit()
}
private func commonInit() {
self.backgroundColor = UIColor.clear
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override open func draw(_ rect: CGRect) {
super.draw(rect)
SPStorkCodeDraw.drawClose(frame: rect, resizing: .aspectFit, color: self.color)
}
}
@@ -21,7 +21,7 @@
import UIKit
class SPStorkIndicatorView: UIView {
open class SPStorkIndicatorView: UIView {
var style: Style = .line {
didSet {
@@ -60,11 +60,11 @@ class SPStorkIndicatorView: UIView {
self.color = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
}
required init?(coder aDecoder: NSCoder) {
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func sizeToFit() {
override open func sizeToFit() {
super.sizeToFit()
self.frame = CGRect.init(x: self.frame.origin.x, y: self.frame.origin.y, width: 36, height: 13)
@@ -21,9 +21,9 @@
import UIKit
public class SPAnimation {
enum SPAnimation {
public static func animate(_ duration: TimeInterval,
static func animate(_ duration: TimeInterval,
animations: (() -> Void)!,
delay: TimeInterval = 0,
options: UIView.AnimationOptions = [],
@@ -40,7 +40,7 @@ public class SPAnimation {
})
}
public static func animateWithRepeatition(_ duration: TimeInterval,
static func animateWithRepeatition(_ duration: TimeInterval,
animations: (() -> Void)!,
delay: TimeInterval = 0,
options: UIView.AnimationOptions = [],
@@ -21,13 +21,13 @@
import UIKit
public class SPAnimationAlpha {
class SPAnimationAlpha {
public static let durationListAnimation: TimeInterval = 0.45
public static let coefLenthForTransition: CGFloat = 2.8
public static let delayPerItem: TimeInterval = 0.09
static let durationListAnimation: TimeInterval = 0.45
static let coefLenthForTransition: CGFloat = 2.8
static let delayPerItem: TimeInterval = 0.09
public static func hideList(_ duration: TimeInterval = durationListAnimation,
static func hideList(_ duration: TimeInterval = durationListAnimation,
views: [UIView],
delayPerItem: TimeInterval = delayPerItem,
withComplection completion: (() -> Void)! = {}) {
@@ -51,7 +51,7 @@ public class SPAnimationAlpha {
}
}
public static func hideReverseList(_ duration: TimeInterval = durationListAnimation,
static func hideReverseList(_ duration: TimeInterval = durationListAnimation,
views: [UIView],
delayPerItem: TimeInterval = delayPerItem,
withComplection completion: (() -> Void)! = {}) {
@@ -76,7 +76,7 @@ public class SPAnimationAlpha {
}
}
public static func showList(_ duration: TimeInterval = durationListAnimation,
static func showList(_ duration: TimeInterval = durationListAnimation,
views: [UIView],
delayPerItem: TimeInterval = delayPerItem,
withComplection completion: (() -> Void)! = {}) {
@@ -21,12 +21,12 @@
import UIKit
public class SPAnimationSpring {
class SPAnimationSpring {
public static let spring: CGFloat = 1
public static let velocity: CGFloat = 1
static let spring: CGFloat = 1
static let velocity: CGFloat = 1
public static func animate(_ duration: TimeInterval,
static func animate(_ duration: TimeInterval,
animations: (() -> Void)!,
delay: TimeInterval = 0,
spring: CGFloat = spring,
@@ -47,7 +47,7 @@ public class SPAnimationSpring {
})
}
public static func animateWithRepeatition(_ duration: TimeInterval,
static func animateWithRepeatition(_ duration: TimeInterval,
animations: (() -> Void)!,
delay: TimeInterval = 0,
spring: CGFloat = spring,
@@ -21,13 +21,13 @@
import UIKit
public class SPAnimationUpward {
class SPAnimationUpward {
public static let durationListAnimation: TimeInterval = 0.45
public static let coefLenthForTransition: CGFloat = 2.8
public static let delayPerItem: TimeInterval = 0.09
static let durationListAnimation: TimeInterval = 0.45
static let coefLenthForTransition: CGFloat = 2.8
static let delayPerItem: TimeInterval = 0.09
public static func hide(_ duration: TimeInterval,
static func hide(_ duration: TimeInterval,
view: UIView,
delay: TimeInterval = 0,
withComplection completion: (() -> Void)! = {}) {
@@ -48,7 +48,7 @@ public class SPAnimationUpward {
})
}
public static func hideList(_ duration: TimeInterval = durationListAnimation,
static func hideList(_ duration: TimeInterval = durationListAnimation,
views: [UIView],
delayPerItem: TimeInterval = delayPerItem,
withComplection completion: (() -> Void)! = {}) {
@@ -69,7 +69,7 @@ public class SPAnimationUpward {
}
public static func show(_ duration: TimeInterval,
static func show(_ duration: TimeInterval,
view: UIView,
delay: TimeInterval = 0,
withComplection completion: (() -> Void)! = {}) {
@@ -93,7 +93,7 @@ public class SPAnimationUpward {
})
}
public static func showList(_ duration: TimeInterval = durationListAnimation,
static func showList(_ duration: TimeInterval = durationListAnimation,
views: [UIView],
delayPerItem: TimeInterval = delayPerItem,
options: UIView.AnimationOptions = [],
@@ -24,19 +24,19 @@ import StoreKit
struct SPApp {
public static var udid: String? {
static var udid: String? {
return UIDevice.current.identifierForVendor?.uuidString
}
public static var displayName: String? {
static var displayName: String? {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
}
public static var rootController: UIViewController? {
static var rootController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController
}
public static var safeArea: UIEdgeInsets {
static var safeArea: UIEdgeInsets {
if #available(iOS 11.0, *) {
return UIApplication.shared.keyWindow?.safeArea ?? UIEdgeInsets.zero
} else {
@@ -44,7 +44,7 @@ struct SPApp {
}
}
public static func set(rootController: UIViewController, animatable: Bool = true) {
static func set(rootController: UIViewController, animatable: Bool = true) {
rootController.view.frame = UIScreen.main.bounds
@@ -65,7 +65,7 @@ struct SPApp {
}
}
public static func set(elementsColor: UIColor) {
static func set(elementsColor: UIColor) {
UINavigationController.elementsColor = elementsColor
UIAlertController.elementsColor = elementsColor
UITabBarController.elementsColor = elementsColor
@@ -23,9 +23,9 @@ import UIKit
extension SPApp {
public struct Badge {
struct Badge {
public static var number: Int {
static var number: Int {
get {
return UIApplication.shared.applicationIconBadgeNumber
}
@@ -34,7 +34,7 @@ extension SPApp {
}
}
public static func reset() {
static func reset() {
UIApplication.shared.applicationIconBadgeNumber = 0
}
@@ -23,25 +23,28 @@ import UIKit
extension SPApp {
public struct Launch {
struct Launch {
public static func run() {
static func run() {
self.count += 1
}
public static var count: Int {
get {
return UserDefaults.standard.value(forKey: "SPLaunchCount") as? Int ?? 0
}
set {
UserDefaults.standard.set(newValue, forKey: "SPLaunchCount")
if (UserDefaults.standard.object(forKey: "SPDateFirstLaunch") as? Date) == nil {
UserDefaults.standard.set(Date(), forKey: "SPDateFirstLaunch")
}
}
public static var isFirstLaunch: Bool {
static var count: Int {
get { return UserDefaults.standard.value(forKey: "SPLaunchCount") as? Int ?? 0 }
set { UserDefaults.standard.set(newValue, forKey: "SPLaunchCount") }
}
static var isFirstLaunch: Bool {
return (self.count == 1) || (self.count == 0)
}
static var dateFirstLaunch: Date {
return ((UserDefaults.standard.object(forKey: "SPDateFirstLaunch") as? Date) ?? Date())
}
private init() {}
}
}
@@ -24,7 +24,7 @@ import SafariServices
extension SPApp {
public static func open(app: SPSystemApp) {
static func open(app: SPSystemApp) {
switch app {
case SPSystemApp.photos:
guard let settingsUrl = URL(string: "photos-redirect://") else {
@@ -63,7 +63,7 @@ extension SPApp {
}
}
public static func open(link: String, redirect: Bool) {
static func open(link: String, redirect: Bool) {
guard let url = URL(string: link) else {
print("SPOpener - can not create URL")
@@ -24,11 +24,11 @@ import StoreKit
struct SPAppStore {
public static func link(appID: String) -> String {
static func link(appID: String) -> String {
return "https://itunes.apple.com/by/app/id" + appID
}
public static func open(app id: String) {
static func open(app id: String) {
if let url = URL(string: "itms-apps://itunes.apple.com/app/id\(id)"),
UIApplication.shared.canOpenURL(url) {
if #available(iOS 10.0, *) {
@@ -39,7 +39,7 @@ struct SPAppStore {
}
}
public static func requestReview(appID: String, force: Bool) {
static func requestReview(appID: String, force: Bool) {
if force {
if let url = URL(string: "itms-apps://itunes.apple.com/us/app/apple-store/id\(appID)?mt=8&action=write-review"),
UIApplication.shared.canOpenURL(url) {
@@ -56,13 +56,13 @@ struct SPAppStore {
}
}
public static func requestReview() {
static func requestReview() {
if #available(iOS 10.3, *) {
SKStoreReviewController.requestReview()
}
}
public static func isUpdateAvailable(completion: @escaping (Bool)->()) {
static func isUpdateAvailable(completion: @escaping (Bool)->()) {
guard let info = Bundle.main.infoDictionary,
let currentVersion = info["CFBundleShortVersionString"] as? String,
@@ -22,9 +22,9 @@
import UIKit
import AVFoundation
public struct SPAudio {
struct SPAudio {
public static func notStopBackgroundMusic() {
static func notStopBackgroundMusic() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category(rawValue: convertFromAVAudioSessionCategory(AVAudioSession.Category.ambient)), mode: AVAudioSession.Mode.default)
try AVAudioSession.sharedInstance().setActive(true)
@@ -22,12 +22,12 @@
import UIKit
import AVFoundation
public class SPAudioPlayer: NSObject, AVAudioPlayerDelegate {
class SPAudioPlayer: NSObject, AVAudioPlayerDelegate {
fileprivate var player: AVAudioPlayer = AVAudioPlayer()
fileprivate var endPlayingComplection: (()->())? = nil
public func play(fileName: String, complection: (()->())? = nil) {
func play(fileName: String, complection: (()->())? = nil) {
self.endPlayingComplection?()
self.player = AVAudioPlayer()
let url = Bundle.main.url(forResource: fileName, withExtension: nil)
@@ -47,11 +47,11 @@ public class SPAudioPlayer: NSObject, AVAudioPlayerDelegate {
}
}
public func stop() {
func stop() {
player.stop()
}
public func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
self.endPlayingComplection?()
}
}
@@ -23,7 +23,7 @@ import UIKit
struct SPBufer {
public static var text: String? {
static var text: String? {
get {
return UIPasteboard.general.string
}
@@ -23,9 +23,9 @@ import UIKit
extension SPCodeDraw {
public class AudioIconPack : NSObject {
class AudioIconPack : NSObject {
@objc dynamic public class func drawPlay(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
@objc dynamic class func drawPlay(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -53,7 +53,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawPause(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
@objc dynamic class func drawPause(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -90,7 +90,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawStop(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
@objc dynamic class func drawStop(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -118,13 +118,13 @@ extension SPCodeDraw {
}
@objc(StyleKitNameResizingBehavior)
public enum ResizingBehavior: Int {
enum ResizingBehavior: Int {
case aspectFit /// The content is proportionally resized to fit into the target rectangle.
case aspectFill /// The content is proportionally resized to completely fill the target rectangle.
case stretch /// The content is stretched to match the entire target rectangle.
case center /// The content is centered in the target rectangle, but it is NOT resized.
public func apply(rect: CGRect, target: CGRect) -> CGRect {
func apply(rect: CGRect, target: CGRect) -> CGRect {
if rect == target || target == CGRect.zero {
return rect
}
@@ -21,4 +21,4 @@
import UIKit
public struct SPCodeDraw { private init() {} }
struct SPCodeDraw { private init() {} }
@@ -23,9 +23,9 @@ import UIKit
extension SPCodeDraw {
public class SocialIconPack : NSObject {
class SocialIconPack : NSObject {
@objc dynamic public class func drawInstagram(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawInstagram(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -115,7 +115,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawVK(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawVK(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -167,7 +167,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawWhatsapp(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawWhatsapp(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -237,7 +237,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawTelegram(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawTelegram(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -313,7 +313,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawFacebook(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 41, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawFacebook(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 41, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -352,7 +352,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawViber(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 41, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawViber(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 41, height: 40), resizing: ResizingBehavior = .aspectFit, fillColor: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -443,13 +443,13 @@ extension SPCodeDraw {
}
@objc(SocialIconStyleKitResizingBehavior)
public enum ResizingBehavior: Int {
enum ResizingBehavior: Int {
case aspectFit /// The content is proportionally resized to fit into the target rectangle.
case aspectFill /// The content is proportionally resized to completely fill the target rectangle.
case stretch /// The content is stretched to match the entire target rectangle.
case center /// The content is centered in the target rectangle, but it is NOT resized.
public func apply(rect: CGRect, target: CGRect) -> CGRect {
func apply(rect: CGRect, target: CGRect) -> CGRect {
if rect == target || target == CGRect.zero {
return rect
}
@@ -23,15 +23,15 @@ import UIKit
extension SPCodeDraw {
public class SystemIconPack : NSObject {
class SystemIconPack : NSObject {
private struct Cache {
static let gradient: CGGradient = CGGradient(colorsSpace: nil, colors: [UIColor.red.cgColor, UIColor.red.cgColor] as CFArray, locations: [0, 1])!
}
@objc dynamic public class var gradient: CGGradient { return Cache.gradient }
@objc dynamic class var gradient: CGGradient { return Cache.gradient }
@objc dynamic public class func drawFavorite(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawFavorite(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -80,7 +80,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawFavoriteFill(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawFavoriteFill(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -113,7 +113,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawShare(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
@objc dynamic class func drawShare(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -154,7 +154,7 @@ extension SPCodeDraw {
context.restoreGState()
}
@objc dynamic public class func drawClose(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
@objc dynamic class func drawClose(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 100, height: 100), resizing: ResizingBehavior = .aspectFit, color: UIColor = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)) {
let context = UIGraphicsGetCurrentContext()!
@@ -192,13 +192,13 @@ extension SPCodeDraw {
}
@objc(StyleKitNameResizingBehavior)
public enum ResizingBehavior: Int {
enum ResizingBehavior: Int {
case aspectFit /// The content is proportionally resized to fit into the target rectangle.
case aspectFill /// The content is proportionally resized to completely fill the target rectangle.
case stretch /// The content is stretched to match the entire target rectangle.
case center /// The content is centered in the target rectangle, but it is NOT resized.
public func apply(rect: CGRect, target: CGRect) -> CGRect {
func apply(rect: CGRect, target: CGRect) -> CGRect {
if rect == target || target == CGRect.zero {
return rect
}
@@ -23,9 +23,9 @@ import UIKit
extension SPCodeDraw {
public class GolubevIconPack : NSObject {
class GolubevIconPack : NSObject {
@objc dynamic public class func drawCamera(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawCamera(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -1494,7 +1494,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawPhotoLibrary(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawPhotoLibrary(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -2229,7 +2229,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawBall(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawBall(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -2855,7 +2855,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawCompass(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawCompass(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -3887,7 +3887,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawMicro(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawMicro(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -4864,7 +4864,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawBook(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawBook(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -5592,7 +5592,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawDocuments(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawDocuments(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -6068,7 +6068,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawCalendar(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawCalendar(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -7465,7 +7465,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawHeadphones(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawHeadphones(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -8248,7 +8248,7 @@ extension SPCodeDraw {
}
@objc dynamic public class func drawWindmill(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
@objc dynamic class func drawWindmill(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 1000, height: 1000), resizing: ResizingBehavior = .aspectFit, white: UIColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.000), light: UIColor = UIColor(red: 0.769, green: 0.847, blue: 0.984, alpha: 1.000), medium: UIColor = UIColor(red: 0.478, green: 0.663, blue: 0.973, alpha: 1.000), dark: UIColor = UIColor(red: 0.000, green: 0.478, blue: 1.000, alpha: 1.000)) {
//// General Declarations
let context = UIGraphicsGetCurrentContext()!
@@ -9119,13 +9119,13 @@ extension SPCodeDraw {
@objc(StyleKitNameResizingBehavior)
public enum ResizingBehavior: Int {
enum ResizingBehavior: Int {
case aspectFit /// The content is proportionally resized to fit into the target rectangle.
case aspectFill /// The content is proportionally resized to completely fill the target rectangle.
case stretch /// The content is stretched to match the entire target rectangle.
case center /// The content is centered in the target rectangle, but it is NOT resized.
public func apply(rect: CGRect, target: CGRect) -> CGRect {
func apply(rect: CGRect, target: CGRect) -> CGRect {
if rect == target || target == CGRect.zero {
return rect
}
@@ -21,9 +21,9 @@
import UIKit
public struct SPConstraints {
struct SPConstraints {
public static func setEqualSizeSuperview(for view: UIView) {
static func setEqualSizeSuperview(for view: UIView) {
if let superView = view.superview {
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
@@ -21,7 +21,7 @@
import Foundation
public func delay(_ delay:Double, closure: @escaping ()->()) {
func delay(_ delay:Double, closure: @escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when) {
closure()
@@ -21,19 +21,19 @@
import UIKit
public struct SPDevice {
struct SPDevice {
public static var iphone: Bool {
static var iphone: Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
public static var ipad: Bool {
static var ipad: Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
public struct Orientation {
struct Orientation {
public static var isPortrait: Bool {
static var isPortrait: Bool {
var isPortraitOrientation = true
if UIDevice.current.orientation.isValidInterfaceOrientation {
if UIDevice.current.orientation.isPortrait {
@@ -23,7 +23,7 @@ import UIKit
struct SPDownloader {
public static func image(link: String, withComplection complection: @escaping (UIImage?) -> ()) {
static func image(link: String, withComplection complection: @escaping (UIImage?) -> ()) {
guard let url = URL(string: link) else {
DispatchQueue.main.async {
complection(nil)
@@ -23,7 +23,7 @@ import Foundation
extension Array {
public func get(count: Int) -> Array {
func get(count: Int) -> Array {
if (count < self.count) { return Array(self[0..<count]) }
return Array(self)
}
@@ -31,7 +31,7 @@ extension Array {
extension Array where Element: Equatable {
public mutating func removeDuplicates() {
mutating func removeDuplicates() {
var result = [Element]()
for value in self {
if result.contains(value) == false { result.append(value) }
@@ -42,8 +42,8 @@ extension Array where Element: Equatable {
extension Array where Element: Hashable {
public func after(item: Element) -> Element? {
if let index = self.index(of: item), index + 1 < self.count { return self[index + 1] }
func after(item: Element) -> Element? {
if let index = self.firstIndex(of: item), index + 1 < self.count { return self[index + 1] }
return nil
}
}
@@ -23,29 +23,29 @@ import UIKit
extension CGRect {
public var bottomX: CGFloat {
var bottomX: CGFloat {
get { return self.origin.x + self.width }
set { self.origin.x = newValue - self.width }
}
public var bottomY: CGFloat {
var bottomY: CGFloat {
get { return self.origin.y + self.height }
set { self.origin.y = newValue - self.height }
}
public var minSide: CGFloat {
var minSide: CGFloat {
return min(self.width, self.height)
}
public mutating func set(width: CGFloat) {
mutating func set(width: CGFloat) {
self = CGRect.init(x: self.origin.x, y: self.origin.y, width: width, height: self.height)
}
public mutating func set(height: CGFloat) {
mutating func set(height: CGFloat) {
self = CGRect.init(x: self.origin.x, y: self.origin.y, width: self.width, height: height)
}
public mutating func set(width: CGFloat, height: CGFloat) {
mutating func set(width: CGFloat, height: CGFloat) {
self = CGRect.init(x: self.origin.x, y: self.origin.y, width: width, height: height)
}
}
@@ -23,13 +23,13 @@ import UIKit
extension CGSize {
public func resize(width: CGFloat) -> CGSize {
func resize(width: CGFloat) -> CGSize {
let relativeSideSize = self.width / self.height
let newHeight = width / relativeSideSize
return CGSize.init(width: width, height: newHeight)
}
public func resize(height: CGFloat) -> CGSize {
func resize(height: CGFloat) -> CGSize {
let relativeSideSize = self.width / self.height
let newWidth = height * relativeSideSize
return CGSize.init(width: newWidth, height: height)
@@ -23,16 +23,20 @@ import Foundation
extension Date {
public func format(mask: String) -> String {
func format(mask: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = mask
return dateFormatter.string(from: self)
}
public static func create(from value: String) -> Date? {
static func create(from value: String) -> Date? {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
let date = formatter.date(from: value)
return date
}
func add(days: Int) -> Date {
return Calendar.current.date(byAdding: .day, value: days, to: self) ?? self
}
}
@@ -23,13 +23,13 @@ import Foundation
extension Strideable {
public mutating func setIfMore(when value: Self) {
mutating func setIfMore(when value: Self) {
if self > value {
self = value
}
}
public mutating func setIfFewer(when value: Self) {
mutating func setIfFewer(when value: Self) {
if self < value {
self = value
}
@@ -24,65 +24,78 @@ import UIKit
extension String {
public var digits: String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
public mutating func dropLast(substring: String) {
mutating func dropLast(substring: String) {
if self.hasSuffix(substring) {
self = String(dropLast(substring.count))
}
}
public mutating func dropFirst(substring: String) {
mutating func dropFirst(substring: String) {
if self.hasPrefix(substring) {
self = String(dropFirst(substring.count))
}
}
public func uppercasedFirstLetter() -> String {
func uppercasedFirstLetter() -> String {
let lowercaseSctring = self.lowercased()
return lowercaseSctring.prefix(1).uppercased() + lowercaseSctring.dropFirst()
}
public mutating func uppercaseFirstLetter() {
mutating func uppercaseFirstLetter() {
self = self.uppercasedFirstLetter()
}
public func removeAllSpaces() -> String {
func removeAllSpaces() -> String {
return self.components(separatedBy: .whitespaces).joined()
}
public mutating func removeAllSpaces() {
mutating func removeAllSpaces() {
self = self.removeAllSpaces()
}
public var isEmail: Bool {
var isEmail: Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailTest.evaluate(with: self)
}
public var isLink: Bool {
var isLink: Bool {
if let url = URL(string: self) {
return UIApplication.shared.canOpenURL(url)
}
return false
}
public var isEmpty: Bool {
var isEmptyContent: Bool {
return (self.removeAllSpaces() == "")
}
public var words: [String] {
var words: [String] {
return components(separatedBy: .punctuationCharacters).joined().components(separatedBy: .whitespaces)
}
public mutating func replace(_ replacingString: String, with newString: String) {
func removePrefix(_ prefix: String) -> String {
guard self.hasPrefix(prefix) else { return self }
return String(self.dropFirst(prefix.count))
}
mutating func replace(_ replacingString: String, with newString: String) {
self = self.replacingOccurrences(of: replacingString, with: newString)
}
public func replace(_ replacingString: String, with newString: String) -> String {
func replace(_ replacingString: String, with newString: String) -> String {
return self.replacingOccurrences(of: replacingString, with: newString)
}
func slice(from: String, to: String) -> String? {
return (range(of: from)?.upperBound).flatMap { substringFrom in
(range(of: to, range: substringFrom..<endIndex)?.lowerBound).map { substringTo in
String(self[substringFrom..<substringTo])
}
}
}
}
@@ -23,7 +23,7 @@ import UIKit
extension UITextField {
@IBInspectable public var placeholderColor: UIColor? {
@IBInspectable var placeholderColor: UIColor? {
get {
return self.placeholderColor
}
@@ -23,7 +23,7 @@ import UIKit
extension UIAlertController {
public static var elementsColor: UIColor {
static var elementsColor: UIColor {
get {
return UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor
}
@@ -32,7 +32,7 @@ extension UIAlertController {
}
}
public static func show(title: String, message: String, buttonTitle: String, cancelButtonTitle: String? = nil, complection: @escaping ()->() = {}, on viewController: UIViewController) {
static func show(title: String, message: String, buttonTitle: String, cancelButtonTitle: String? = nil, complection: @escaping ()->() = {}, on viewController: UIViewController) {
let ac = UIAlertController(
title: title,
message: message,
@@ -56,7 +56,7 @@ extension UIAlertController {
viewController.present(ac, animated: true, completion: nil)
}
public static func сonfirm(title: String? = nil, message: String, buttonTitle: String, cancelButtonTitle: String, isDestructive: Bool = false, complection: @escaping (Bool)->(), on viewController: UIViewController) {
static func сonfirm(title: String? = nil, message: String, buttonTitle: String, cancelButtonTitle: String, isDestructive: Bool = false, complection: @escaping (Bool)->(), on viewController: UIViewController) {
let ac = UIAlertController(
title: title,
message: message,
@@ -83,21 +83,21 @@ extension UIAlertController {
extension UIAlertController {
public func addAction(title: String, complection: @escaping ()->()) {
func addAction(title: String, complection: @escaping ()->()) {
let action = UIAlertAction(title: title, style: .default) { (action) in
complection()
}
self.addAction(action)
}
public func addDestructiveAction(title: String, complection: @escaping ()->()) {
func addDestructiveAction(title: String, complection: @escaping ()->()) {
let action = UIAlertAction(title: title, style: .destructive) { (action) in
complection()
}
self.addAction(action)
}
public func addCancelAction(title: String, complection: @escaping ()->() = {}) {
func addCancelAction(title: String, complection: @escaping ()->() = {}) {
let action = UIAlertAction(title: title, style: .cancel) { (action) in
complection()
}
@@ -23,7 +23,7 @@ import UIKit
extension UIButton {
public typealias UIButtonTargetClosure = () -> ()
typealias UIButtonTargetClosure = () -> ()
private class ClosureWrapper: NSObject {
let closure: UIButtonTargetClosure
@@ -47,7 +47,7 @@ extension UIButton {
}
}
public func target(_ action: @escaping UIButtonTargetClosure) {
func target(_ action: @escaping UIButtonTargetClosure) {
targetClosure = action
addTarget(self, action: #selector(UIButton.targetAction), for: .touchUpInside)
}
@@ -60,28 +60,28 @@ extension UIButton {
extension UIButton {
public func setTitle(_ title: String, color: UIColor? = nil) {
func setTitle(_ title: String, color: UIColor? = nil) {
self.setTitle(title, for: .normal)
if let color = color {
self.setTitleColor(color)
}
}
public func setTitleColor(_ color: UIColor) {
func setTitleColor(_ color: UIColor) {
self.setTitleColor(color, for: .normal)
self.setTitleColor(color.withAlphaComponent(0.7), for: .highlighted)
}
public func setImage(_ image: UIImage) {
func setImage(_ image: UIImage) {
self.setImage(image, for: .normal)
self.imageView?.contentMode = .scaleAspectFit
}
public func removeAllTargets() {
func removeAllTargets() {
self.removeTarget(nil, action: nil, for: .allEvents)
}
public func showText(_ text: String, withComplection completion: (() -> Void)! = {}) {
func showText(_ text: String, withComplection completion: (() -> Void)! = {}) {
let baseText = self.titleLabel?.text ?? " "
SPAnimation.animate(0.2, animations: {
self.titleLabel?.alpha = 0
@@ -105,7 +105,7 @@ extension UIButton {
})
}
public func setAnimatableText(_ text: String, withComplection completion: (() -> Void)! = {}) {
func setAnimatableText(_ text: String, withComplection completion: (() -> Void)! = {}) {
SPAnimation.animate(0.3, animations: {
self.titleLabel?.alpha = 0
}, withComplection: {
@@ -118,7 +118,7 @@ extension UIButton {
})
}
public func hideContent(completion: (() -> Void)! = {}) {
func hideContent(completion: (() -> Void)! = {}) {
SPAnimation.animate(0.25, animations: {
self.titleLabel?.alpha = 0
}, withComplection: {
@@ -126,7 +126,7 @@ extension UIButton {
})
}
public func showContent(completion: (() -> Void)! = {}) {
func showContent(completion: (() -> Void)! = {}) {
SPAnimation.animate(0.25, animations: {
self.titleLabel?.alpha = 1
}, withComplection: {
@@ -23,10 +23,34 @@ import UIKit
extension UICollectionView {
public var currentIndexCellPath: IndexPath? {
var currentIndexCellPath: IndexPath? {
let visibleRect = CGRect(origin: self.contentOffset, size: self.bounds.size)
let visiblePoint = CGPoint.init(x: visibleRect.midX, y: visibleRect.midY)
let visibleIndexPath = self.indexPathForItem(at: visiblePoint)
return visibleIndexPath
}
func lastRow(indexPath: IndexPath) -> Int {
return self.numberOfItems(inSection: indexPath.section) - 1
}
func isLastRow(indexPath: IndexPath) -> Bool {
return indexPath.row == self.lastRow(indexPath: indexPath)
}
func reloadData(animated: Bool, complection: @escaping ()->() = {}) {
if animated {
UIView.transition(
with: self,
duration: 0.3,
options: [.transitionCrossDissolve, UIView.AnimationOptions.beginFromCurrentState],
animations: {
self.reloadData()
}, completion: {(state) in
complection()
})
} else {
self.reloadData()
}
}
}
@@ -21,9 +21,9 @@
import UIKit
public extension UIColor {
extension UIColor {
public convenience init(hex: String) {
convenience init(hex: String) {
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
@@ -21,9 +21,9 @@
import UIKit
public extension UIFont {
extension UIFont {
public static func system(weight: FontWeight, size: CGFloat) -> UIFont {
static func system(weight: FontWeight, size: CGFloat) -> UIFont {
return UIFont.systemFont(ofSize: size, weight: self.weight(for: weight))
}
@@ -48,7 +48,7 @@ public extension UIFont {
}
}
public enum FontWeight {
enum FontWeight {
case regular
case medium
case light
@@ -21,9 +21,9 @@
import UIKit
public extension UIImage {
extension UIImage {
public func resize(width: CGFloat) -> UIImage {
func resize(width: CGFloat) -> UIImage {
let scale = width / self.size.width
let newHeight = self.size.height * scale
UIGraphicsBeginImageContext(CGSize(width: width, height: newHeight))
@@ -23,13 +23,13 @@ import UIKit
extension UIImageView {
public func setNative() {
func setNative() {
self.layer.borderWidth = 0.5
self.layer.borderColor = SPNativeColors.midGray.cgColor
self.layer.masksToBounds = true
}
public func downloadedFrom(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, withComplection complection: @escaping (UIImage?) -> () = {_ in }) {
func downloadedFrom(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, withComplection complection: @escaping (UIImage?) -> () = {_ in }) {
DispatchQueue.main.async {
self.contentMode = mode
}
@@ -47,7 +47,7 @@ extension UIImageView {
}.resume()
}
public func downloadedFrom(link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, withComplection complection: @escaping (UIImage?) -> () = {_ in }) {
func downloadedFrom(link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, withComplection complection: @escaping (UIImage?) -> () = {_ in }) {
guard let url = URL(string: link) else { return }
downloadedFrom(url: url, contentMode: mode, withComplection: complection)
}
@@ -21,9 +21,9 @@
import UIKit
public extension UILabel {
extension UILabel {
public func setShadowOffsetForLetters(blurRadius: CGFloat = 0, widthOffset: CGFloat = 0, heightOffset: CGFloat, opacity: CGFloat) {
func setShadowOffsetForLetters(blurRadius: CGFloat = 0, widthOffset: CGFloat = 0, heightOffset: CGFloat, opacity: CGFloat) {
self.layer.shadowRadius = blurRadius
self.layer.shadowOffset = CGSize(
width: widthOffset,
@@ -32,29 +32,29 @@ public extension UILabel {
self.layer.shadowOpacity = Float(opacity)
}
public func setShadowOffsetFactorForLetters(blurRadius: CGFloat = 0, widthOffsetFactor: CGFloat = 0, heightOffsetFactor: CGFloat, opacity: CGFloat) {
func setShadowOffsetFactorForLetters(blurRadius: CGFloat = 0, widthOffsetFactor: CGFloat = 0, heightOffsetFactor: CGFloat, opacity: CGFloat) {
let widthOffset = widthOffsetFactor * self.frame.width
let heightOffset = heightOffsetFactor * self.frame.height
self.setShadowOffsetForLetters(blurRadius: blurRadius, widthOffset: widthOffset, heightOffset: heightOffset, opacity: opacity)
}
public func removeShadowForLetters() {
func removeShadowForLetters() {
self.setShadowOffsetForLetters(blurRadius: 0, widthOffset: 0, heightOffset: 0, opacity: 0)
}
public func setCenterAlignment() {
func setCenterAlignment() {
self.textAlignment = .center
self.baselineAdjustment = .alignCenters
}
public func setLettersSpacing(_ value: CGFloat) {
func setLettersSpacing(_ value: CGFloat) {
if let textString = text {
let attrs: [NSAttributedString.Key : Any] = [.kern: value]
attributedText = NSAttributedString(string: textString, attributes: attrs)
}
}
public func setLineSpacing(_ lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
func setLineSpacing(_ lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
guard let labelText = self.text else { return }
@@ -73,4 +73,21 @@ public extension UILabel {
self.attributedText = attributedString
}
func setFormat(text: String, positions: [(start: Int, length: Int)], hithiglightFont: UIFont, higlightColor: UIColor) {
let title = NSMutableAttributedString.init(string: text)
for position in positions {
title.addAttributes(
[
NSAttributedString.Key.foregroundColor : higlightColor,
NSAttributedString.Key.font : hithiglightFont
],
range: NSRange.init(location: position.start, length: position.length)
)
}
self.attributedText = title
}
}
@@ -23,7 +23,7 @@ import UIKit
extension UINavigationController {
public static var elementsColor: UIColor {
static var elementsColor: UIColor {
get {
if UINavigationBar.appearance().tintColor != nil {
return UINavigationBar.appearance().tintColor
@@ -23,7 +23,7 @@ import UIKit
extension UITabBarController {
public static var elementsColor: UIColor {
static var elementsColor: UIColor {
get {
if UITabBar.appearance().tintColor != nil {
return UITabBar.appearance().tintColor
@@ -36,7 +36,7 @@ extension UITabBarController {
}
}
public func addTabBarItem(title: String, image: UIImage, selectedImage: UIImage? = nil, controller: UIViewController) {
func addTabBarItem(title: String, image: UIImage, selectedImage: UIImage? = nil, controller: UIViewController) {
let tabBarItem = UITabBarItem(
title: title,
@@ -23,19 +23,19 @@ import UIKit
extension UITableView {
public var isEmpty: Bool {
var isEmpty: Bool {
return self.lastSectionWithRows == nil
}
public func isEmpty(section: Int) -> Bool {
func isEmpty(section: Int) -> Bool {
return self.numberOfRows(inSection: section) == 0
}
public var lastSection: Int {
var lastSection: Int {
return self.numberOfSections - 1
}
public var lastSectionWithRows: Int? {
var lastSectionWithRows: Int? {
if self.numberOfSections == 0 { return nil }
var section = self.numberOfSections - 1
if section < 0 { return nil }
@@ -46,7 +46,7 @@ extension UITableView {
return nil
}
public var firstSectionWithRows: Int? {
var firstSectionWithRows: Int? {
if self.numberOfSections == 0 { return nil }
var section = 0
if section > self.numberOfSections - 1 { return nil }
@@ -23,11 +23,11 @@ import UIKit
extension UITableViewCell {
public var accessoryView: UIView? {
var accessoryView: UIView? {
return subviews.compactMap { $0 as? UIButton }.first
}
public var highlightedColor: UIColor? {
var highlightedColor: UIColor? {
get {
return self.backgroundView?.backgroundColor
}
@@ -38,7 +38,7 @@ extension UITableViewCell {
}
}
public func highlight() {
func highlight() {
self.setHighlighted(true, animated: false)
self.setHighlighted(false, animated: true)
}
@@ -23,7 +23,7 @@ import UIKit
extension UITextField {
public var isEmptyText: Bool {
var isEmptyText: Bool {
get {
if self.text == "" {
return true
@@ -24,15 +24,15 @@ import Photos
extension UIViewController {
public func present(_ viewControllerToPresent: UIViewController, completion: (() -> Swift.Void)? = nil) {
func present(_ viewControllerToPresent: UIViewController, completion: (() -> Swift.Void)? = nil) {
self.present(viewControllerToPresent, animated: true, completion: completion)
}
@objc public func dismiss() {
@objc func dismiss() {
self.dismiss(animated: true, completion: nil)
}
public func wrapToNavigationController(statusBar: SPStatusBar = .dark) -> UINavigationController {
func wrapToNavigationController(statusBar: SPStatusBar = .dark) -> UINavigationController {
let controller = SPStatusBarManagerNavigationController(rootViewController: self)
controller.statusBar = statusBar
return controller
@@ -41,20 +41,20 @@ extension UIViewController {
extension UIViewController {
public func dismissKeyboardWhenTappedAround() {
func dismissKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc public func dismissKeyboard() {
@objc func dismissKeyboard() {
view.endEditing(true)
}
}
extension UIViewController {
public func save(image: UIImage) {
func save(image: UIImage) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
} else {
@@ -62,7 +62,7 @@ extension UIViewController {
}
}
public func saveVideo(url: String, complection: @escaping (Bool)->()) {
func saveVideo(url: String, complection: @escaping (Bool)->()) {
DispatchQueue.global(qos: .utility).async {
let urls = URL(string: url)
let urldata = try? Data(contentsOf: urls!)
@@ -90,7 +90,7 @@ extension UIViewController {
}
}
@objc public func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let _ = error {
self.imageSaved(isSuccses: false)
} else {
@@ -98,14 +98,14 @@ extension UIViewController {
}
}
@objc public func imageSaved(isSuccses: Bool) {
@objc func imageSaved(isSuccses: Bool) {
fatalError("SPUIViewControllerExtenshion - Need ovveride 'imageSaved' func")
}
}
extension UIViewController {
public func setPrefersLargeNavigationTitle(_ title: String, smallScreenToSmallBar: Bool = true) {
func setPrefersLargeNavigationTitle(_ title: String, smallScreenToSmallBar: Bool = true) {
self.navigationItem.title = title
if #available(iOS 11.0, *) {
self.navigationItem.largeTitleDisplayMode = .automatic
@@ -119,7 +119,7 @@ extension UIViewController {
}
}
public func setNavigationTitle(_ title: String, style: SPNavigationTitleStyle) {
func setNavigationTitle(_ title: String, style: SPNavigationTitleStyle) {
self.navigationItem.title = title
switch style {
case .large:
@@ -135,13 +135,17 @@ extension UIViewController {
if #available(iOS 11.0, *) {
self.navigationItem.largeTitleDisplayMode = .never
}
case .noContent:
if #available(iOS 11.0, *) {
self.navigationItem.largeTitleDisplayMode = .never
}
}
}
}
extension UIViewController {
public var safeArea: UIEdgeInsets {
var safeArea: UIEdgeInsets {
if #available(iOS 11.0, *) {
return self.view.safeAreaInsets
} else {
@@ -149,18 +153,18 @@ extension UIViewController {
}
}
public var navigationBarHeight: CGFloat {
var navigationBarHeight: CGFloat {
return self.navigationController?.navigationBar.frame.height ?? 0
}
public static var statusBarHeight: CGFloat {
static var statusBarHeight: CGFloat {
return UIApplication.shared.statusBarFrame.height
}
}
extension UIViewController {
public var navigationTitleColor: UIColor? {
var navigationTitleColor: UIColor? {
get {
return (self.navigationController?.navigationBar.titleTextAttributes?[NSAttributedString.Key.foregroundColor] as? UIColor) ?? nil
}
@@ -21,20 +21,20 @@
import UIKit
public extension UIView {
extension UIView {
public var viewController: UIViewController? {
var controller: UIViewController? {
get {
if let nextResponder = self.next as? UIViewController { return nextResponder }
else if let nextResponder = self.next as? UIView { return nextResponder.viewController }
else if let nextResponder = self.next as? UIView { return nextResponder.controller }
else { return nil }
}
}
}
public extension UIView {
extension UIView {
public var safeArea: UIEdgeInsets {
var safeArea: UIEdgeInsets {
if #available(iOS 11.0, *) {
return self.safeAreaInsets
} else{
@@ -42,11 +42,11 @@ public extension UIView {
}
}
public func setBounds(_ view: UIView, withWidthFactor widthFactor: CGFloat = 1, maxWidth: CGFloat? = nil, withHeightFactor heightFactor: CGFloat = 1, maxHeight: CGFloat? = nil, withCentering: Bool = false) {
func setBounds(_ view: UIView, withWidthFactor widthFactor: CGFloat = 1, maxWidth: CGFloat? = nil, withHeightFactor heightFactor: CGFloat = 1, maxHeight: CGFloat? = nil, withCentering: Bool = false) {
self.setBounds(view.bounds, withWidthFactor: widthFactor, maxWidth: maxWidth, withHeightFactor: heightFactor, maxHeight: maxHeight, withCentering: withCentering)
}
public func setBounds(_ bounds: CGRect, withWidthFactor widthFactor: CGFloat = 1, maxWidth: CGFloat? = nil, withHeightFactor heightFactor: CGFloat = 1, maxHeight: CGFloat? = nil, withCentering: Bool = false) {
func setBounds(_ bounds: CGRect, withWidthFactor widthFactor: CGFloat = 1, maxWidth: CGFloat? = nil, withHeightFactor heightFactor: CGFloat = 1, maxHeight: CGFloat? = nil, withCentering: Bool = false) {
var width = bounds.width * widthFactor
if maxWidth != nil { width.setIfMore(when: maxWidth!) }
@@ -62,7 +62,7 @@ public extension UIView {
}
}
public func setSuperviewBounds(customWidth: CGFloat? = nil, customHeight: CGFloat? = nil) {
func setSuperviewBounds(customWidth: CGFloat? = nil, customHeight: CGFloat? = nil) {
if self.superview == nil { return }
self.frame = CGRect.init(origin: CGPoint.zero, size: self.superview!.frame.size)
if customWidth != nil {
@@ -73,7 +73,7 @@ public extension UIView {
}
}
public func resize(width: CGFloat) {
func resize(width: CGFloat) {
let relativeFactor = self.frame.width / self.frame.height
if relativeFactor.isNaN { return }
self.frame = CGRect.init(
@@ -84,7 +84,7 @@ public extension UIView {
)
}
public func resize(height: CGFloat) {
func resize(height: CGFloat) {
let relativeFactor = self.frame.width / self.frame.height
if relativeFactor.isNaN { return }
self.frame = CGRect.init(
@@ -95,27 +95,27 @@ public extension UIView {
)
}
public func setYCenter() {
func setYCenter() {
self.center.y = (self.superview?.frame.height ?? 0) / 2
}
public func setXCenter() {
func setXCenter() {
self.center.x = (self.superview?.frame.width ?? 0) / 2
}
public func setToCenter() {
func setToCenter() {
self.center = CGPoint.init(x: ((self.superview?.frame.width) ?? 0) / 2, y: ((self.superview?.frame.height) ?? 0) / 2)
}
}
public extension UIView {
extension UIView {
public func setParalax(amountFactor: CGFloat) {
func setParalax(amountFactor: CGFloat) {
let amount = self.frame.minSide * amountFactor
self.setParalax(amount: amount)
}
public func setParalax(amount: CGFloat) {
func setParalax(amount: CGFloat) {
self.motionEffects.removeAll()
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -amount
@@ -131,9 +131,9 @@ public extension UIView {
}
}
public extension UIView {
extension UIView {
public func addGrade(alpha: CGFloat, color: UIColor = UIColor.black) -> UIView {
func addGrade(alpha: CGFloat, color: UIColor = UIColor.black) -> UIView {
let gradeView = UIView.init()
gradeView.alpha = 0
self.addSubview(gradeView)
@@ -146,7 +146,7 @@ public extension UIView {
extension UIView {
public func setShadow(
func setShadow(
xTranslationFactor: CGFloat,
yTranslationFactor: CGFloat,
widthRelativeFactor: CGFloat,
@@ -178,7 +178,7 @@ extension UIView {
self.layer.shadowPath = shadowPath.cgPath;
}
public func setShadow(
func setShadow(
xTranslation: CGFloat,
yTranslation: CGFloat,
widthRelativeFactor: CGFloat,
@@ -203,14 +203,14 @@ extension UIView {
self.layer.shadowPath = shadowPath.cgPath
}
public func removeShadow() {
func removeShadow() {
self.layer.shadowColor = nil
self.layer.shadowOffset = CGSize.zero
self.layer.shadowOpacity = 0
self.layer.shadowPath = nil
}
public func addShadowOpacityAnimation(to: CGFloat, duration: CFTimeInterval) {
func addShadowOpacityAnimation(to: CGFloat, duration: CFTimeInterval) {
let animation = CABasicAnimation(keyPath:"shadowOpacity")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
animation.fromValue = self.layer.cornerRadius
@@ -224,7 +224,7 @@ extension UIView {
extension UIView {
public func addCornerRadiusAnimation(to: CGFloat, duration: CFTimeInterval) {
func addCornerRadiusAnimation(to: CGFloat, duration: CFTimeInterval) {
let animation = CABasicAnimation(keyPath:"cornerRadius")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
animation.fromValue = self.layer.cornerRadius
@@ -234,14 +234,14 @@ extension UIView {
self.layer.cornerRadius = to
}
public func show(duration: TimeInterval = 0.3) {
func show(duration: TimeInterval = 0.3) {
self.isHidden = false
SPAnimation.animate(duration, animations: {
self.alpha = 1
})
}
public func hide(duration: TimeInterval = 0.3) {
func hide(duration: TimeInterval = 0.3) {
SPAnimation.animate(duration, animations: {
self.alpha = 0
}, withComplection: {
@@ -249,21 +249,21 @@ extension UIView {
})
}
public func removeAllAnimations() {
func removeAllAnimations() {
self.layer.removeAllAnimations()
}
}
extension UIView {
public func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
public func round() {
func round() {
self.layer.cornerRadius = self.frame.minSide / 2
}
}
@@ -23,12 +23,12 @@ import UIKit
extension UIVisualEffectView {
public convenience init(style: UIBlurEffect.Style) {
convenience init(style: UIBlurEffect.Style) {
let effect = UIBlurEffect(style: style)
self.init(effect: effect)
}
public convenience init(vibrancy style: UIBlurEffect.Style) {
convenience init(vibrancy style: UIBlurEffect.Style) {
let effect = UIBlurEffect(style: style)
let vibrancyEffect = UIVibrancyEffect(blurEffect: effect)
self.init(effect: vibrancyEffect)
@@ -23,15 +23,15 @@ import Foundation
extension UserDefaults {
public func set(stringArray array: [String], forKey key: String) {
func set(stringArray array: [String], forKey key: String) {
self.set(array, forKey: key)
}
public func set(boolArray array: [Bool], forKey key: String) {
func set(boolArray array: [Bool], forKey key: String) {
self.set(array, forKey: key)
}
public func boolArray(forKey defaultName: String) -> [Bool] {
func boolArray(forKey defaultName: String) -> [Bool] {
return UserDefaults.standard.array(forKey: defaultName) as? [Bool] ?? []
}
}
@@ -21,9 +21,9 @@
import UIKit
public struct SPLayout {
struct SPLayout {
public static func sizeWith(widthFactor: CGFloat, maxWidth: CGFloat?, heightFactor: CGFloat, maxHeight: CGFloat?, relativeSideFactor: CGFloat?, from size: CGSize) -> CGSize {
static func sizeWith(widthFactor: CGFloat, maxWidth: CGFloat?, heightFactor: CGFloat, maxHeight: CGFloat?, relativeSideFactor: CGFloat?, from size: CGSize) -> CGSize {
var widthArea = size.width * widthFactor
var heightArea = size.height * heightFactor
@@ -24,7 +24,7 @@ import LocalAuthentication
struct SPLocalAuthentication {
public static var isEnable: Bool {
static var isEnable: Bool {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
@@ -38,7 +38,7 @@ struct SPLocalAuthentication {
}
}
public static func request(reason: String, complecton: @escaping (Bool)->()) {
static func request(reason: String, complecton: @escaping (Bool)->()) {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
@@ -21,7 +21,7 @@
import UIKit
public enum SPLocale: String, CaseIterable {
enum SPLocale: String, CaseIterable {
case ru = "ru"
case en = "en"
@@ -24,11 +24,11 @@ import MessageUI
struct SPMail {
public static var canSendEmail: Bool {
static var canSendEmail: Bool {
return MFMailComposeViewController.canSendMail()
}
public static func openApp(to email: String, subject: String? = nil, body: String? = nil) {
static func openApp(to email: String, subject: String? = nil, body: String? = nil) {
let parametrs = "mailto:\(email)?subject=\(subject ?? "")&body=\(body ?? "")".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
if parametrs != nil {
@@ -40,7 +40,7 @@ struct SPMail {
}
}
public static func dialog(to email: String, subject: String? = nil, body: String? = nil, on viewController: UIViewController) {
static func dialog(to email: String, subject: String? = nil, body: String? = nil, on viewController: UIViewController) {
let mailVC = MFMailComposeViewController()
mailVC.mailComposeDelegate = SPMailSingltone.sharedInstance
@@ -21,21 +21,21 @@
import UIKit
public enum SPNativeColors {
enum SPNativeColors {
public static let red = UIColor.init(hex: "FF3B30")
public static let orange = UIColor.init(hex: "FF9500")
public static let yellow = UIColor.init(hex: "FFCC00")
public static let green = UIColor.init(hex: "4CD964")
public static let tealBlue = UIColor.init(hex: "5AC8FA")
public static let blue = UIColor.init(hex: "007AFF")
public static let purple = UIColor.init(hex: "5856D6")
public static let pink = UIColor.init(hex: "FF2D55")
public static let white = UIColor.init(hex: "FFFFFF")
public static let customGray = UIColor.init(hex: "EFEFF4")
public static let lightGray = UIColor.init(hex: "E5E5EA")
public static let lightGray2 = UIColor.init(hex: "D1D1D6")
public static let midGray = UIColor.init(hex: "C7C7CC")
public static let gray = UIColor.init(hex: "8E8E93")
public static let black = UIColor.init(hex: "000000")
static let red = UIColor.init(hex: "FF3B30")
static let orange = UIColor.init(hex: "FF9500")
static let yellow = UIColor.init(hex: "FFCC00")
static let green = UIColor.init(hex: "4CD964")
static let tealBlue = UIColor.init(hex: "5AC8FA")
static let blue = UIColor.init(hex: "007AFF")
static let purple = UIColor.init(hex: "5856D6")
static let pink = UIColor.init(hex: "FF2D55")
static let white = UIColor.init(hex: "FFFFFF")
static let customGray = UIColor.init(hex: "EFEFF4")
static let lightGray = UIColor.init(hex: "E5E5EA")
static let lightGray2 = UIColor.init(hex: "D1D1D6")
static let midGray = UIColor.init(hex: "C7C7CC")
static let gray = UIColor.init(hex: "8E8E93")
static let black = UIColor.init(hex: "000000")
}
@@ -22,24 +22,28 @@
import UIKit
import UserNotifications
public struct SPLocalNotification {
struct SPLocalNotification {
public static func add(from timeInterval: TimeInterval, body: String, title: String? = nil, identifier: String? = nil) {
let content = UNMutableNotificationContent()
content.body = body
content.title = title ?? ""
content.badge = NSNumber(value: 1)
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
let identifier = identifier ?? "\(timeInterval)\(body)\(Int.random(min: 0, max: 1000))"
var identificator: String? = nil
var text: String
var title: String? = nil
var badge: Int = 0
var timeInterval: TimeInterval
var soundEnabled: Bool = true
var category: SPLocalNotificationCategory? = nil
init(after timeInterval: TimeInterval, text: String) {
self.text = text
self.timeInterval = timeInterval
}
func add() {
let identificator = self.identificator ?? "\(self.timeInterval)\(self.text)\(Int.random(min: 0, max: 1000))"
let notification = UNNotificationRequest(
identifier: identifier,
content: content,
trigger: trigger
identifier: identificator,
content: self.content,
trigger: self.trigger
)
let center = UNUserNotificationCenter.current()
@@ -50,37 +54,35 @@ public struct SPLocalNotification {
}
}
public static func add(in date: Date, body: String, title: String? = nil, identifier: String? = nil) {
private var content: UNMutableNotificationContent {
let content = UNMutableNotificationContent()
content.body = body
content.title = title ?? ""
content.badge = NSNumber(value: 1)
content.sound = UNNotificationSound.default
content.body = self.text
content.title = self.title ?? ""
content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + self.badge)
content.sound = self.soundEnabled ? UNNotificationSound.default : nil
let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second,], from: date)
let trigger = UNCalendarNotificationTrigger.init(dateMatching: triggerDate, repeats: false)
let identifier = identifier ?? "\(date)\(body)\(Int.random(min: 0, max: 1000))"
let notification = UNNotificationRequest(
identifier: identifier,
content: content,
trigger: trigger
)
let center = UNUserNotificationCenter.current()
center.add(notification) { (error) in
if let error = error {
print("SPLocalNotification - \(error)")
if let category = self.category {
if #available(iOS 12.0, *) {
let notificationCategory = UNNotificationCategory(identifier: category.identifier, actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: nil, categorySummaryFormat: category.summary, options: [])
UNUserNotificationCenter.current().setNotificationCategories([notificationCategory])
content.categoryIdentifier = notificationCategory.identifier
}
}
return content
}
public static func remove(identifier: String) {
let center = UNUserNotificationCenter.current()
center.removePendingNotificationRequests(withIdentifiers: [identifier])
private var trigger: UNTimeIntervalNotificationTrigger {
return UNTimeIntervalNotificationTrigger(timeInterval: self.timeInterval, repeats: false)
}
}
struct SPLocalNotificationCategory {
var identifier: String
var summary: String
var countSymbol: String {
return "%u"
}
private init() {}
}
@@ -21,9 +21,9 @@
import UIKit
public extension String {
extension String {
public static func random(count: Int) -> String {
static func random(count: Int) -> String {
let strings = [
"В доме кардинала от меня не было тайн; не раз видел я, как он усердно перелистывает старинные книги и жадно роется в пыли фамильных рукописей. Когда я как-то упрекнул его за бесполезные бессонные ночи, после которых он впадал в болезненное уныние, он взглянул на меня с горькой улыбкой и раскрыл передо мною историю города Рима. В этой книге, в двадцатой главе жизнеописания папы Александра Шестого, я прочел следующие строки, навсегда оставшиеся в моей памяти",
"По этому поводу между отцом и сыном завязался спор. Цезарь считал, что достаточно применить одно из тех средств, которые он всегда держал наготове для своих ближайших друзей, а именно: пресловутый ключ, которым то одного, то другого просили отпереть некий шкаф. На ключе был крохотный железный шип – недосмотр слесаря. Каждый, кто трудился над тугим замком, накалывал себе палец и на другой день умирал. Был еще перстень с львиной головой, который Цезарь надевал, когда хотел пожать руку той или иной особе. Лев впивался в кожу этих избранных рук, и через сутки наступала смерть.",
@@ -34,70 +34,61 @@ public extension String {
}
}
public extension Int {
extension Int {
public static func random(_ n: Int) -> Int {
return Int(arc4random_uniform(UInt32(n)))
static func random() -> Int {
return Int.random(in: 0...Int.max)
}
public static func random(min: Int, max: Int) -> Int {
return Int(arc4random_uniform(UInt32(max - min - 1))) + min
static func random(min: Int, max: Int) -> Int {
return Int.random(in: min...max)
}
}
public extension Double {
extension Double {
public static func random() -> Double {
return Double(arc4random()) / 0xFFFFFFFF
static func random() -> Double {
return Double.random(in: 0...Double.greatestFiniteMagnitude)
}
public static func random(min: Double, max: Double) -> Double {
return Double.random() * (max - min) + min
static func random(min: Double, max: Double) -> Double {
return Double.random(in: min...max)
}
}
public extension Float {
extension Float {
public static func random() -> Float {
return Float(arc4random()) / 0xFFFFFFFF
static func random() -> Float {
return Float.random(in: 0...Float.greatestFiniteMagnitude)
}
public static func random(min: Float, max: Float) -> Float {
return Float.random() * (max - min) + min
static func random(min: Float, max: Float) -> Float {
return Float.random(in: min...max)
}
}
public extension CGFloat {
extension CGFloat {
public static func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
static func random() -> CGFloat {
return CGFloat.random(in: 0...CGFloat.greatestFiniteMagnitude)
}
public static func random(min: CGFloat, max: CGFloat) -> CGFloat {
return CGFloat.random() * (max - min) + min
}
}
public extension Collection {
public func shuffle() -> [Iterator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
static func random(min: CGFloat, max: CGFloat) -> CGFloat {
return CGFloat.random(in: min...max)
}
}
extension Collection where Index == Int {
public func random() -> Iterator.Element? {
func random() -> Iterator.Element? {
return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
}
}
public extension MutableCollection where Index == Int {
extension MutableCollection where Index == Int {
mutating func shuffleInPlace() {
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
@@ -21,4 +21,4 @@
import Foundation
public struct SPShadow { private init() {} }
struct SPShadow { private init() {} }
@@ -23,17 +23,17 @@ import UIKit
extension SPShadow {
public struct DeepStyle {
struct DeepStyle {
private init() {}
public static func setFor(label: UILabel) {
static func setFor(label: UILabel) {
var offset = label.frame.height * 0.03
offset.setIfMore(when: 1)
label.setShadowOffsetForLetters(heightOffset: offset, opacity: 0.35)
}
public static func setFor(view: UIView) {
static func setFor(view: UIView) {
let xTranslationFactor: CGFloat = 0
let yTranslationFactor: CGFloat = 0.18
@@ -85,14 +85,14 @@ extension SPShadow {
extension UIView {
public func setDeepShadow() {
func setDeepShadow() {
SPShadow.DeepStyle.setFor(view: self)
}
}
extension UILabel {
public func setDeepShadowForLetters() {
func setDeepShadowForLetters() {
SPShadow.DeepStyle.setFor(label: self)
}
}
@@ -21,11 +21,11 @@
import UIKit
public struct SPShare {
struct SPShare {
public struct Native {
struct Native {
public static func share(text: String? = nil, fileNames: [String] = [], images: [UIImage] = [], complection: ((_ isSharing: Bool)->())? = nil, sourceView: UIView, on viewController: UIViewController) {
static func share(text: String? = nil, fileNames: [String] = [], images: [UIImage] = [], complection: ((_ isSharing: Bool)->())? = nil, sourceView: UIView, on viewController: UIViewController) {
var shareData: [Any] = []
if text != nil {
@@ -21,13 +21,13 @@
import UIKit
public class SPInstagram {
class SPInstagram {
public static var isSetApp: Bool {
static var isSetApp: Bool {
return UIApplication.shared.canOpenURL(URL(string: "instagram://user?username=test")!)
}
public static func openPost(id: String) {
static func openPost(id: String) {
let instagramHooks = "instagram://media?id=\(id)"
let instagramUrl = URL(string: instagramHooks)
let safariURL = URL(string: "instagram.com/\(id)")!
@@ -38,7 +38,7 @@ public class SPInstagram {
}
}
public static func openUser(username: String) {
static func openUser(username: String) {
let instagramHooks = "instagram://user?username=\(username)"
let instagramUrl = URL(string: instagramHooks)
let safariURL = URL(string: "https://instagram.com/\(username)")!
@@ -21,13 +21,13 @@
import UIKit
public class SPTelegram {
class SPTelegram {
public static var isSetApp: Bool {
static var isSetApp: Bool {
return UIApplication.shared.canOpenURL(URL(string: "tg://msg?text=test")!)
}
public static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
let urlStringEncoded = text.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed)
let urlOptional = URL(string: "tg://msg?text=\(urlStringEncoded ?? "")")
if let url = urlOptional {
@@ -41,12 +41,36 @@ public class SPTelegram {
}
}
public static func joinChannel(id: String) {
static func joinChannel(id: String) {
let url = "https://t.me/joinchat/\(id)"
SPApp.open(link: url, redirect: true)
}
public static func openBot(username: String) {
static func joinChat(id: String) {
let openInBrowser = {
let url = "https://t.me/joinchat/\(id)"
SPApp.open(link: url, redirect: true)
}
if SPTelegram.isSetApp {
let urlStringEncoded = id.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed)
let urlOptional = URL(string: "tg://join?invite=\(urlStringEncoded ?? "")")
if let url = urlOptional {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
openInBrowser()
}
} else {
openInBrowser()
}
} else {
openInBrowser()
}
}
static func openBot(username: String) {
var username = username
if username.first == "@" {
username.removeFirst()
@@ -59,5 +83,5 @@ public class SPTelegram {
}
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -21,13 +21,13 @@
import UIKit
public class SPTwitter {
class SPTwitter {
public static var isSetApp: Bool {
static var isSetApp: Bool {
return UIApplication.shared.canOpenURL(URL(string: "twitter://post?message=test")!)
}
public static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
let urlStringEncoded = text.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed)
let urlOptional = URL(string: "twitter://post?message=\(urlStringEncoded ?? "")")
if let url = urlOptional {
@@ -21,13 +21,13 @@
import UIKit
public class SPViber {
class SPViber {
public static var isSetApp: Bool {
static var isSetApp: Bool {
return UIApplication.shared.canOpenURL(URL(string: "viber://forward?text=test")!)
}
public static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
let urlStringEncoded = text.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed)
let urlOptional = URL(string: "viber://forward?text=\(urlStringEncoded ?? "")")
if let url = urlOptional {
@@ -21,13 +21,13 @@
import UIKit
public class SPWhatsApp {
class SPWhatsApp {
public static var isSetApp: Bool {
static var isSetApp: Bool {
return UIApplication.shared.canOpenURL(URL(string: "whatsapp://send?text=test")!)
}
public static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
let urlStringEncoded = text.addingPercentEncoding( withAllowedCharacters: .urlHostAllowed)
let urlOptional = URL(string: "whatsapp://send?text=\(urlStringEncoded ?? "")")
if let url = urlOptional {
@@ -21,19 +21,19 @@
import UIKit
public enum SPStatusBar {
enum SPStatusBar {
case dark
case light
}
public enum SPSystemIcon {
enum SPSystemIcon {
case share
case close
case favorite
case favorite_fill
}
public enum SPSocialNetwork {
enum SPSocialNetwork {
case whatsapp
case telegram
case vk
@@ -41,7 +41,7 @@ public enum SPSocialNetwork {
case viber
}
public enum SPOauthState {
enum SPOauthState {
case succsess
case unvalidLogin
case invalidLogin
@@ -51,25 +51,26 @@ public enum SPOauthState {
case error
}
public enum SPSeparatorInsetStyle {
enum SPSeparatorInsetStyle {
case beforeImage
case all
case none
case auto
}
public enum SPNavigationTitleStyle {
enum SPNavigationTitleStyle {
case large
case small
case stork
case noContent
}
public enum SPSystemApp {
enum SPSystemApp {
case photos
case setting
}
public enum SPSelectionType {
enum SPSelectionType {
case select
case unselect
}
@@ -21,7 +21,7 @@
import UIKit
public class SPAppStoreActionButton: SPDownloadingButton {
class SPAppStoreActionButton: SPDownloadingButton {
var style: Style = .base {
didSet {
@@ -78,7 +78,7 @@ public class SPAppStoreActionButton: SPDownloadingButton {
self.layer.masksToBounds = true
}
override public func setTitle(_ title: String?, for state: UIControl.State) {
override func setTitle(_ title: String?, for state: UIControl.State) {
switch self.style {
case .base:
super.setTitle(title?.uppercased(), for: state)
@@ -91,7 +91,7 @@ public class SPAppStoreActionButton: SPDownloadingButton {
}
}
override public func layoutSubviews() {
override func layoutSubviews() {
super.layoutSubviews()
if self.style == .buyInStore {
self.layer.cornerRadius = 12

Some files were not shown because too many files have changed in this diff Show More