380 Commits

Author SHA1 Message Date
E L V I S 6f0ead5af5 Update Lightbox.podspec 2020-07-09 19:47:10 -05:00
E L V I S 4a70c08f37 Merge pull request #254 from hyperoslo/force-modalPresentationStyle
Force modal presentation style
2020-07-09 19:46:46 -05:00
Elvis 7830a7512a Add comment 2020-07-09 19:45:55 -05:00
Elvis 2bb85661b1 Force usage of modalPresentationStyle 2020-07-09 19:44:03 -05:00
Elvis dbffe4f688 Update demo to fix broken link and to show label bug 2020-06-22 08:29:04 -05:00
Elvis ed69a9fdee Add navigation controller to demo 2020-06-22 08:22:00 -05:00
E L V I S 6344062be2 Update Lightbox.podspec 2020-06-22 08:17:15 -05:00
Elvis 8dcf50b722 Add backup symbol for play button 2020-06-22 08:16:07 -05:00
E L V I S 3c145a392b Update README.md 2020-06-22 07:57:52 -05:00
Elvis 25e4877614 Fix demo 2020-06-22 07:56:43 -05:00
Elvis 18743a36a5 Update project 2020-06-17 11:56:23 -05:00
E L V I S 8e254accd6 Merge pull request #248 from Tobisaninfo/master
Introduce Swift Package Manager
2020-06-15 12:27:06 -05:00
E L V I S d3e8d79d27 Merge pull request #249 from yspreen/master
Add cache to carthage requirements.
2020-06-15 12:26:28 -05:00
Yannick Spreen e3b2df4363 Add cache to carthage requirements. 2020-06-15 09:05:56 -04:00
tobias c25bbf4671 Fix source path in Package.swift 2020-06-14 20:14:13 +02:00
tobias c0e7c31844 Add Package.swift 2020-06-14 20:12:31 +02:00
Elvis e43ba2b58f Move example project 2020-06-13 21:26:18 -05:00
E L V I S 6d92df2dad Delete .swift-version 2020-06-08 18:50:50 -05:00
E L V I S 5b85a492a6 Update README.md 2020-06-08 18:50:18 -05:00
Elvis 774947dea5 Update demo 2020-06-08 18:47:11 -05:00
Elvis 21d6b335fc Update sample project 2020-06-08 18:36:01 -05:00
Elvis b45f490bec Update project 2020-06-08 17:52:51 -05:00
E L V I S b37e139060 Merge pull request #246 from hyperoslo/update-swift-5
Update swift 5
2020-06-08 17:51:12 -05:00
Elvis 1e3636cebf Update all the thing 2020-06-08 17:50:09 -05:00
Elvis 54bb598dd8 Bump podspec 2020-06-07 01:42:26 -05:00
Khoa 1aa9643feb Merge pull request #218 from ndonald2/color-extension-fix
Change UIColor hex extension to internal visibility
2019-02-13 17:54:34 +01:00
Nick Donaldson 1bccfe2cc1 Change UIColor hex extension to internal visibility
Using public visibility means that developers are unable to
simultaneously use hypersolo/Hue along with Lightbox since
both modules contain a globally imported extension of the
same format - UIColor.init(hex: String)
2019-01-04 11:03:32 -07:00
Khoa Pham 1b16b2bb74 Update podspec 2018-09-27 10:55:35 +02:00
Khoa Pham 32c45514c8 Update demo 2018-09-27 10:51:16 +02:00
Khoa Pham e73f58ced5 Update to Swift 4 2018-09-27 10:47:47 +02:00
Khoa 54b73d3cc0 Merge pull request #206 from fassko/master
Swift 4.2 and Xcode 10
2018-09-27 10:39:35 +02:00
Kristaps Grinbergs 8fc34e8d12 Two issues need to fix for Swift 4.2 2018-09-26 10:18:38 +03:00
Kristaps Grinbergs 6af9321ea9 * Swift 4.2 and Xcode 10
* SwiftLint warnings and errors, added some short variable names in config
* Example project to Swift 4.2 and Xcode 10
* bump version
2018-09-23 13:25:03 +03:00
Khoa 1584281c41 Merge pull request #182 from t0a0/Image_preload_constant
Added possibility to set image preload value
2018-05-16 13:44:04 +02:00
Igor Fedotov 5ac3f8ae18 fixed typo 2018-02-13 19:45:21 +01:00
Igor Fedotov 5d93293649 upd range syntax for consistency 2018-02-13 19:42:53 +01:00
Igor Fedotov a4f113d066 updated lightbox controller to handle preload 2018-02-13 19:37:50 +01:00
Igor Fedotov 41436d8083 This unloads the image when the pageView is stubbed 2018-02-13 19:31:59 +01:00
Igor Fedotov 22785514bd Add variable to config, to allow preload 2018-02-13 18:58:09 +01:00
Igor Fedotov d8f6836c0f forgot to commit xcode files for the stub 2018-02-13 18:57:34 +01:00
Igor Fedotov 20ea9e3e1c Added private init method on LightboxImage to support the stub 2018-02-13 18:56:07 +01:00
Igor Fedotov 64dee3b6bc Added a subclass to stub the images, that do not need to be loaded 2018-02-13 18:55:31 +01:00
Igor Fedotov 911d0c5df8 Made PageView able to update with image 2018-02-13 18:52:33 +01:00
Igor Fedotov cc85786658 Fixed unnecessar call, that was making images to be fetched twice 2018-02-13 17:03:14 +01:00
Vadym Markov 3b695da3ee Merge pull request #181 from t0a0/Support_for_init_with_closure
Added support to init with closure
2018-02-12 23:14:26 +01:00
Igor Fedotov 5a73ca4c6b Added support to init with closure 2018-02-12 22:59:12 +01:00
Khoa Pham 90d31b75ca Bump to 2.1.2 2018-01-02 12:21:59 +01:00
Khoa 9d6d6e3798 Merge pull request #172 from hyperoslo/fix/page
Fix footer frame
2018-01-02 12:11:46 +01:00
Khoa Pham 81e13530aa Set size and origin 2018-01-02 11:45:41 +01:00
Khoa Pham f11af83808 Update dependencies in demo 2018-01-02 11:39:38 +01:00
Christoffer Winterkvist 162f6d29c3 Merge pull request #167 from vincentsaluzzo/master
Carthage compatibility
2017-12-09 20:32:28 +01:00
Vincent Saluzzo cb97450102 remove copy framework build phase which should make only on app building and not framework (nested framework aren't allowed by Apple) 2017-12-08 12:07:09 +01:00
Khoa 9de5f16735 Merge pull request #163 from rinat-enikeev/fix-footer-counter
Fix footer counter
2017-11-27 13:59:07 +01:00
Rinat Enikeev 418da11c82 fix footer counter
reason: you should take into account spacing while calculating current page
2017-11-27 17:45:30 +05:00
Khoa Pham 90fe59ffc6 Bump to 2.1.1 2017-11-21 14:24:34 +01:00
Khoa Pham 422b23b4c2 Update README.md 2017-11-21 10:41:26 +01:00
Khoa Pham 08a4c284f4 Merge pull request #156 from andreyrd/fix/no-window-bounds
Use view.bounds instead of UIApplicationDelegate.window.bounds
2017-11-20 21:59:07 +01:00
Khoa Pham b775f12fe5 Merge pull request #157 from hyperoslo/fix/truncating
Add test
2017-11-20 15:47:17 +01:00
Khoa Pham 9f75ddffdf Use just 1 test 2017-11-20 14:53:21 +01:00
Khoa Pham 225fac033a Remove fileprivate in order to test 2017-11-20 14:49:26 +01:00
Khoa Pham fe3229278d Add test 2017-11-20 14:48:57 +01:00
Khoa Pham de0d273258 Add quotes 2017-11-20 14:26:01 +01:00
Khoa Pham d1231f19ff Fix swiftlint warnings 2017-11-20 14:25:33 +01:00
Khoa Pham 20f927f338 Need to greater than startIndex 2017-11-20 14:22:40 +01:00
Andrey Radchishin 8144d96129 Use view.bounds instead of UIApplicationDelegate.window.bounds 2017-11-17 10:11:20 -08:00
Khoa Pham 0d9e3ef7ab Bump to 2.1.0 2017-11-17 16:21:51 +01:00
Khoa Pham 888067cae0 Merge pull request #155 from hyperoslo/fix/image_download
Allow custom download
2017-11-17 16:21:18 +01:00
Khoa Pham 0180ca76c7 Update README 2017-11-17 15:16:20 +01:00
Khoa Pham 951b95b0fb Update README 2017-11-17 15:08:28 +01:00
Khoa Pham 1803722b6a Expose LightboxConfig.loadImage. Use Imaginary by default 2017-11-17 15:04:31 +01:00
Khoa Pham 4f5ee72f97 Merge pull request #154 from hyperoslo/fix/layout
Update layout for iPhone X
2017-11-17 14:45:57 +01:00
Khoa Pham 9e17ebb58f Update README with 2 screenshots 2017-11-17 14:37:59 +01:00
Khoa Pham 28acb5a8d6 Layout HeaderView 2017-11-17 14:30:47 +01:00
Khoa Pham 5c6fa430e0 Remove HeaderView animation when dismissasl 2017-11-17 14:27:27 +01:00
Khoa Pham 5108f3651f Remove centerTextStyle 2017-11-17 14:26:59 +01:00
Khoa Pham 05ec840ffd Fix indentation 2017-11-17 14:20:20 +01:00
Khoa Pham 5189d880c4 Should not animate FooterView upon dismissal animation 2017-11-17 14:17:02 +01:00
Khoa Pham 308051a898 Remove unused isUserInteractionEnabled 2017-11-17 14:04:00 +01:00
Khoa Pham 56481d5f8a Update description text 2017-11-17 13:55:48 +01:00
Khoa Pham 3882befd7b Layout FooterView in viewDidLayoutSubviews 2017-11-17 13:52:50 +01:00
Khoa Pham cf88115eb6 Use view bounds instead of UIScreen 2017-11-17 13:31:56 +01:00
Khoa Pham 663bafce52 Use bottomPadding for pageLabel 2017-11-17 13:19:45 +01:00
Khoa Pham 6911104a98 Use topPadding for HeaderView buttons 2017-11-17 12:51:26 +01:00
Vadym Markov 369252ee7c Merge pull request #152 from andreyrd/string-characters-deprecated
Use String directly instead of String.characters
2017-11-13 20:08:00 +01:00
Andrey Radchishin 3322107688 Use String directly instead of String.characters 2017-11-13 09:02:46 -08:00
Khoa Pham 7731adc79c Update README.md 2017-11-06 12:15:10 +01:00
Khoa Pham 5c48b2482a Bump to 2.0.1 2017-11-02 13:03:21 +01:00
Khoa Pham 83416d6870 Merge pull request #147 from hyperoslo/fix/carthage
Update Carthage
2017-11-02 13:02:44 +01:00
Khoa Pham 4f9540b4df Update Cartfile 2017-11-02 12:57:58 +01:00
Khoa Pham 304c3e61f6 Just run carthage update 2017-11-02 12:51:28 +01:00
Khoa Pham 026153f502 Merge pull request #143 from bchrobot/fix-index-error
Refactored truncatedText getter to prevent occasional EXC_BREAKPOINT crash
2017-10-15 18:20:15 +02:00
Benjamin Chrobot 6e53ee01c7 Refactored truncatedText getter to prevent occassional 'EXC_BREAKPOINT: cannot decrement invalid index' crash. 2017-10-13 13:49:51 -04:00
Khoa Pham 9882c474a6 Merge pull request #139 from hyperoslo/swift4
Swift4
2017-10-03 15:33:55 +02:00
Khoa Pham 593c2ac5f3 Merge from master 2017-10-03 14:47:18 +02:00
Khoa Pham 23340fc075 Update demo 2017-10-03 14:44:55 +02:00
Khoa Pham 0bd57097aa Lock dependencies versions 2017-10-03 14:41:40 +02:00
Khoa Pham 9ede29331a Make demo app universal 2017-10-03 14:34:08 +02:00
Khoa Pham 8f51e95e35 Add emojis 2017-10-03 14:34:02 +02:00
Khoa Pham eb4b12f633 Bump 1.1.0 2017-10-03 13:34:07 +02:00
Khoa Pham c00d8b62dd Update demo 2017-10-03 13:31:18 +02:00
Khoa Pham 0d60426da2 Lock to 2.0 2017-10-03 13:28:30 +02:00
Khoa Pham fec46dbd52 Merge pull request #138 from TParizek/master
Specified Hue dependency version in podspec - Issue 137
2017-10-03 13:26:01 +02:00
Tomáš Pařízek 54da63c4a1 Specified Hue dependency version in podspec 2017-10-02 14:16:02 +02:00
Khoa Pham 9d0a0a9811 Merge pull request #136 from hyperoslo/fix/config
Allow loadingIndicator to be configured
2017-09-26 16:22:46 +02:00
Khoa Pham 401cfe185a Use loadingIndicator from Config 2017-09-26 14:41:16 +02:00
Khoa Pham db80c7384c Add comments. Add makeLoadingIndicator 2017-09-26 14:40:46 +02:00
Khoa Pham d03d724746 Merge pull request #135 from hyperoslo/fix/imaginary
Add Imaginary
2017-09-25 16:41:08 +02:00
Khoa Pham cb583ef202 Add bootstrap scripts for Carthage 2017-09-25 16:30:20 +02:00
Khoa Pham d92b2c3e79 Add comments 2017-09-25 16:20:21 +02:00
Khoa Pham d0923f2660 Remove typealias 2017-09-25 16:15:16 +02:00
Khoa Pham 961020ea94 Update demo 2017-09-25 16:14:39 +02:00
Khoa Pham 8867836ff5 Use Imaginary to load image 2017-09-25 16:06:16 +02:00
Khoa Pham aec061594d Add Imaginary 2017-09-25 16:01:57 +02:00
Khoa Pham 45abbf66ad Disable Swift 3 @objc Inference 2017-09-25 15:40:28 +02:00
Khoa Pham 59d59bd532 Use swift 4 2017-09-25 15:39:22 +02:00
Khoa Pham 29f5e05f1b Add circle CI 2017-09-25 15:38:40 +02:00
Khoa Pham 7885828fa3 Use latest version of Hue 2017-09-25 15:36:30 +02:00
Khoa Pham a69fb3da17 Use swift 4 2017-09-25 15:35:28 +02:00
Khoa Pham 0e16f68dc1 Remove travis 2017-09-25 15:34:47 +02:00
Khoa Pham 5cd6b4b698 Merge pull request #134 from mhassanpur/master
Fixes Swift 4 errors and warnings
2017-09-25 15:32:37 +02:00
Mujtaba Hassanpur b5d86f1f79 Fixes more issues with @objc modifier on configureLayout() methods 2017-09-21 10:28:51 -07:00
Mujtaba Hassanpur 68a429be43 Fixes Swift 4 errors and warnings 2017-09-20 21:14:45 -07:00
Christoffer Winterkvist ec1200faea Merge pull request #129 from r-mckay/feature/useSwiftLint
project: use swiftlint and fix triggered warnings
2017-09-03 14:32:32 +02:00
Romain Bertozzi f0825e09d5 source: fix SwiftLint unused closure parameters
This commit fixes several warnings concerning unused closure parameters.
2017-09-02 12:23:47 -04:00
Romain Bertozzi 1e354c2675 source: fix SwiftLint option redondant init
This commit fixes a SwiftLint Option Redondant Initialization warning in
a file.
2017-09-02 12:19:36 -04:00
Romain Bertozzi eade5ac4c8 source: fix SwiftLint colon violation
This commit takes care of fixing a SwiftLint Colon Violation in a file.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 8a33f9529b source: fix SwiftLint parameter alignement violation
This commit aligns parameters in a call to fix a SwiftLint warning.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 4abeb93ac7 source: remove trailing spaces
This commit solves the SwiftLint warning concerning the trailing spaces.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 619f84d89e project: add build phase running SwiftLint
This commit adds a build phase to the project to run SwiftLint. This new
phase follows the implementation made in the ImagePicker project [1].

This commit does not try to handle the eventual warning that could be
raised by the static code analysis.

[1] https://github.com/hyperoslo/ImagePicker
2017-09-02 12:19:36 -04:00
Christoffer Winterkvist 9531315c94 Merge pull request #123 from ShaneQi/fix_hide_status_bar_and_footer_gradient
Fixed two bugs.
2017-09-01 09:03:37 +02:00
Vadym Markov cfafbbcb14 Merge pull request #127 from r-mckay/fix/resolveWarning
lightboxController: fix warning
2017-08-27 19:40:37 +02:00
Shane Qi 6a6096e0b8 Fixed footer view gradient.
Should remove gradient layer if infoLabel's text is empty, regardless expanded state.

This is a override commit, in order to run CI again.
2017-08-26 19:54:37 -05:00
Romain Bertozzi 1480a44dfb lightboxController: fix warning
This commit fixes a warning indicating that a variable value was never
mutated and should be a constant.

To fix this warning we actually replace the 'var' by a 'let'.
2017-08-26 17:45:00 -04:00
Christoffer Winterkvist 2687d175c1 Merge pull request #128 from r-mckay/fix/continuousIntegration
project: update continuous integration setup
2017-08-26 13:51:32 +02:00
Romain Bertozzi c84682d3d9 project: update continuous integration setup
This commit updates the continuous integration setup by selecting the
Xcode 8.3 osx_image and by indicating that the project is written in
swift.
2017-08-25 16:12:33 -04:00
Shane Qi 6627936d23 Fixed status bar hidden config.
Switched from `UIApplication.shared.setStatusBarHidden` to `prefersStatusBarHidden`.
2017-07-13 18:06:38 -05:00
onmyway133 b26ee135bc Merge pull request #120 from vitalii-tym/fix/issue108
Updating the image frames while images are still being loaded
2017-06-20 15:11:00 +02:00
onmyway133 96d7da82bb Merge pull request #119 from vitalii-tym/fix/issue117
Cutting long texts quicker
2017-06-20 15:07:01 +02:00
onmyway133 9707c7cfe4 Merge pull request #122 from vitalii-tym/improvement/accessible-images
Updating the .image property of a LightboxImage instance after Lightbox has downloaded an image via URL
2017-06-20 11:31:28 +02:00
Vitaliy Tim 4968853f8c Made image property of LightBox images accessible after the image has been loaded via URL 2017-06-20 11:29:48 +03:00
Vitaliy Tim 053735d408 Properly updating the image frames while images are still being loaded, so that activity indicators are correcty shown 2017-06-20 10:59:38 +03:00
Vitaliy Tim 6052398040 Speeding up cutting process for long texts 2017-06-20 10:39:18 +03:00
onmyway133 df48ce7b85 Merge pull request #112 from danwilliams64/fix/screen_bounds
Use key window bounds instead of screen bounds
2017-06-19 12:46:00 +02:00
Dan Williams eb44646978 Use app delegate's window instead of screen bounds 2017-06-19 11:30:35 +01:00
onmyway133 6686d8f83b Merge pull request #113 from vitalii-tym/master
Preserve correct Navigation Bar after dismissal when opened from a controller with a Nav Bar
2017-06-19 11:30:30 +02:00
Vitaliy Tim 03be7479f4 Fixes an issue with Navigation Bar, which had wrong position after the lightbox has been dismissed 2017-06-19 11:50:09 +03:00
Christoffer Winterkvist 3b54e8959d Merge pull request #107 from hyperoslo/improve/dynamic-background
Fix dynamic background loading
2017-04-25 12:33:20 +02:00
Christoffer Winterkvist 69813ee7fe Fix dynamic background loading
Because `loadDynamicBackground` is called in `remoteImageDidLoad`, it
can end up flickering between all images as they are loaded from the
network. To fix this issue there is a now a small safeguard in
`remoteImageDidLoad` to evaluate if the image view is on screen,
otherwise just return early and don't switch out the background.

The `PageViewDelegate` has been slightly modified to return the image
view when loading remote images, that image view is used in the safe
guard mentioned earlier.

The `addìmageTo` now uses a weak reference to reduce the chance of
holding reference.

`addGradientLayer` now uses `@discardableResult` so that you don't have
to assign it to a variable when using the method.

The `goTo` method in `LightboxController` will no disregard the
animation if the controller is not on screen. This is done by checking
if the controller's view as a window or not.
2017-04-25 07:28:13 +02:00
Vadym Markov 4ccab620d6 Merge pull request #104 from rmnblm/master
Auto-size Close and Delete buttons
2017-04-21 09:37:55 +02:00
Roman Blum 3ea5a88e01 change 4 spaces to 2 spaces 2017-04-21 09:36:51 +02:00
Roman Blum 2b9216b1b8 auto-size Close and Delete buttons 2017-03-14 09:26:02 +01:00
Khoa Pham 48f307b003 Merge pull request #103 from rmnblm/master
Fix half-black screen after dismissal
2017-03-02 15:00:16 +01:00
Roman Blum eb44c67f69 Fix half-black screen after dismissal 2017-03-02 12:06:42 +01:00
John Sundell e6452f116e Merge pull request #94 from basecom/master
Added new protocol LightboxControllerTouchDelegate
2017-02-14 09:56:02 +01:00
Christoph Dieckmann 96c660a424 Added new protocol LightboxControllerTouchDelegate to delegate the touch event to the calling object. 2017-02-07 14:35:16 +01:00
Vadym Markov 4833dcde35 Update README.md 2016-12-21 15:17:16 +01:00
Vadym Markov 8f907c1fe9 Update README.md 2016-12-21 15:10:40 +01:00
Vadym Markov e314fea3e7 Update summary 2016-12-21 14:36:07 +01:00
Vadym Markov b4ec75ca27 Add swift version 2016-12-21 14:34:18 +01:00
Vadym Markov f483716859 Merge pull request #91 from hyperoslo/rename/example
Rename Demo to Example
2016-12-21 14:29:40 +01:00
Vadym Markov 83397dc491 Rename Demo to Example 2016-12-21 14:29:17 +01:00
Vadym Markov f2319d70f8 Update Lightbox.podspec 2016-12-21 14:24:59 +01:00
Christoffer Winterkvist 2d03d8a7e1 Merge pull request #87 from hyperoslo/swift-3
Swift 3
2016-12-21 14:19:23 +01:00
Vadym Markov 04437d8450 Add icon to readme 2016-12-21 14:16:45 +01:00
Vadym Markov d31d74d0b5 Resolve conflicts 2016-12-21 14:15:01 +01:00
Christoffer Winterkvist 40730ff2c5 Merge pull request #86 from hyperoslo/feature/readme
Feature/readme
2016-12-19 15:05:40 +01:00
Vadym Markov fa965b8a15 Fix typos 2016-12-19 14:57:14 +01:00
Vadym Markov 90c8c87565 Remove links 2016-12-19 14:20:39 +01:00
Vadym Markov dbac1b89e3 Add readme 2016-12-19 14:01:42 +01:00
Vadym Markov 770af6fcdc Update demo 2016-12-19 14:01:34 +01:00
Vadym Markov c1be7f8d71 Carthage update 2016-12-19 14:01:21 +01:00
Christoffer Winterkvist c8a2b2be8a Merge pull request #85 from hyperoslo/fix/dismiss_controls
Hide controls upon single tap
2016-12-11 17:34:18 +01:00
Khoa Pham b525124b3e Add Lightbox.bundle 2016-12-09 21:37:59 +01:00
Khoa Pham a74e9ff7ee Add single tap gesture recognizer 2016-12-09 16:42:46 +01:00
Khoa Pham 40f6bd91c7 Run pod install 2016-12-09 15:46:27 +01:00
Khoa Pham e465067217 Merge pull request #84 from hyperoslo/fix/resources
Move image files into Resources folder
2016-11-10 12:51:18 +01:00
Hyperseed 002dd5558b Update resource path 2016-11-10 12:51:06 +01:00
Hyperseed cfacb850f9 Move image files into Resources folder 2016-11-10 12:44:23 +01:00
Khoa Pham 98e3f62ebe Remove Sugar 2016-10-17 10:52:21 +02:00
Khoa Pham b6d1a36ee5 Use white indicator view 2016-10-17 10:42:20 +02:00
Khoa Pham 345bbd55b3 Update demo 2016-10-17 10:40:23 +02:00
Khoa Pham 701ae968b9 Add loading indicator 2016-10-17 10:30:20 +02:00
Khoa Pham 01d697f1f5 Point dependencies to master 2016-10-17 10:30:09 +02:00
Christoffer Winterkvist f0589a307c Disable emails on travis 2016-10-13 09:46:20 +02:00
Christoffer Winterkvist 23b49e9535 Carthage update 2016-10-13 09:46:15 +02:00
Khoa Pham 66f6d69121 Merge pull request #83 from hyperoslo/fix/loading_indicator
Add loading indicator
2016-09-30 09:03:54 +02:00
Khoa Pham 7bb0628b42 Show loading indicator when loading images 2016-09-29 12:13:04 +02:00
Khoa Pham 5b439af899 Add loading indicator 2016-09-29 11:55:28 +02:00
Khoa Pham c4f2df441f Allow arbitrary requests 2016-09-29 11:44:53 +02:00
Ramon Gilabert b1c7001b3b Removes a Travis line 2016-09-29 10:43:01 +02:00
Ramon Gilabert d70305993a Adds the new Travis 2016-09-29 10:36:06 +02:00
Ramon Gilabert a6119a3cc0 Updates the demo 2016-09-28 16:33:28 +02:00
Ramon Gilabert d1b82ee0d6 Adds the Carthage migration 2016-09-28 16:15:36 +02:00
Vadym Markov 0495a8c547 Merge pull request #80 from hyperoslo/fix/video
Video support
2016-08-08 15:31:42 +02:00
Khoa Pham b3abbd1f7a Update playButton 2016-08-07 16:52:52 +02:00
Khoa Pham 7edaaa9e69 Show and hide play button 2016-08-07 16:43:41 +02:00
Khoa Pham e6b3e5a23b Check for videoURL 2016-08-07 16:35:22 +02:00
Khoa Pham a0d45b7faf Handle video url 2016-08-07 16:30:47 +02:00
Khoa Pham ec74f08998 pod install 2016-08-07 16:30:47 +02:00
Christoffer Winterkvist 87949871e1 Merge pull request #78 from hyperoslo/fix/strong-reference
Fix strong reference
2016-06-06 13:01:55 +02:00
Christoffer Winterkvist 597181b672 Back to let 2016-06-06 12:48:26 +02:00
Christoffer Winterkvist c6795ad84d Fix lint warnings 2016-06-06 12:42:51 +02:00
Christoffer Winterkvist ddc67ff70b Make LightboxController weak 2016-06-06 12:42:45 +02:00
Christoffer Winterkvist ee9fc3dac9 Pod update 2016-06-06 12:42:35 +02:00
Christoffer Winterkvist e46ac10e84 Add .swiftlint.yml 2016-06-06 12:42:26 +02:00
Christoffer Winterkvist da39d8a72e Merge pull request #76 from hyperoslo/fix/public
Use public private(set)
2016-04-22 10:04:40 +02:00
Khoa Pham 222414ecaf Use public private(set) 2016-04-21 22:37:53 +02:00
Vadym Markov 5af42a50ad Merge pull request #75 from hyperoslo/fix/delete_animation
Adjust to make removal anomation more smooth
2016-04-15 14:52:54 +02:00
Vadym Markov 84db79b258 Merge pull request #74 from hyperoslo/improve/expand_animation
Add animation when changing alpha
2016-04-15 14:52:21 +02:00
Khoa Pham 9328d6af4e Adjust to make removal anomation more smooth 2016-04-14 09:19:42 +02:00
Khoa Pham 513d988939 Use trailing closure 2016-04-14 08:42:04 +02:00
Christoffer Winterkvist 35997d1e33 Merge pull request #72 from aashishdhawan/refactor/private-var
Making var private
2016-04-13 23:09:41 +02:00
Khoa Pham 4cef861fe9 Add animation when changing alpha 2016-04-13 16:41:33 +02:00
Christoffer Winterkvist 981fe7a222 Update travis.yml 2016-04-03 19:08:48 +02:00
Ramon Gilabert 1499bf5ecf Merge pull request #73 from hyperoslo/improve/swift-2.2
Update to Swift 2.2 syntax
2016-03-29 09:28:31 +02:00
Khoa Pham b8eacf9682 Use #selector and new range constructor 2016-03-29 09:25:16 +02:00
Aashish Dhawan 6a36b73105 Making var private 2016-02-22 23:10:49 +05:30
Vadym Markov 7f71186b9f Merge pull request #71 from hyperoslo/fix/crash
Fix crash when compiling in release mode
2016-02-22 09:37:26 +01:00
Christoffer Winterkvist 94c0969f6a Fix crash when compiling in release mode 2016-02-22 09:22:17 +01:00
Ramon Gilabert 92768bec5c Merge pull request #68 from hyperoslo/fix/presented
Fix presented property
2016-02-11 14:10:52 +01:00
Vadym Markov a4e4f1363f Fix status bar 2016-02-11 14:08:20 +01:00
Vadym Markov 2050f6d220 Configure layout on view did appear 2016-02-11 14:05:32 +01:00
Christoffer Winterkvist c0b5dc713f Merge pull request #67 from hyperoslo/fix/configure-pages
Fix a crash with configure pages in the init
2016-02-11 13:18:52 +01:00
Vadym Markov d805d1ff99 Change initial vars to let 2016-02-11 13:10:52 +01:00
Vadym Markov 2752b4c213 Move configuration to viewDidLoad 2016-02-11 11:58:01 +01:00
Vadym Markov f625c8dcf5 Change back to class 2016-02-11 11:57:47 +01:00
Vadym Markov 67d3ad03d4 Pod update 2016-02-11 11:57:27 +01:00
Ramon Gilabert 67d52df14d Merge pull request #66 from hyperoslo/fix/struct-lightbox-image
Lightbox image is a struct now
2016-02-10 15:21:26 +01:00
Vadym Markov a6d21f4488 Lightbox image is a struct now 2016-02-10 15:20:12 +01:00
Ramon Gilabert 7f0a6198f7 Merge pull request #65 from hyperoslo/fix/dynamic-background-for-remote-images
Fix dynamic background for remote images
2016-02-10 09:15:33 +01:00
Christoffer Winterkvist b1e2191471 Refactor to use guard 2016-02-10 08:59:57 +01:00
Christoffer Winterkvist 289954e998 Update travis.yml 2016-02-10 08:52:45 +01:00
Christoffer Winterkvist 012ac4f7a0 Pass remote image back in closure 2016-02-10 08:49:12 +01:00
Christoffer Winterkvist 3a2f9293a9 Make LightboxController conform to PageViewDelegate 2016-02-10 08:48:59 +01:00
Christoffer Winterkvist 36ef02a69a Add remoteImageDidLoad on PageViewDelegate 2016-02-10 08:48:37 +01:00
Christoffer Winterkvist 737ccdc826 Use imageView.image to get the image on load 2016-02-10 08:48:24 +01:00
Christoffer Winterkvist b37a1267d4 Refactor loading dynamic background into its own method 2016-02-10 08:48:09 +01:00
Christoffer Winterkvist de3405b655 Add remote image 2016-02-10 08:47:29 +01:00
Christoffer Winterkvist a52c22c4fd Allow loading remote images in demo 2016-02-10 08:47:25 +01:00
Ramon Gilabert 236b3fb8ea Merge pull request #64 from hyperoslo/feature/configuration
Feature: configuration
2016-02-01 16:44:15 +01:00
Vadym Markov 97de34d528 Make delete button hidden by default 2016-02-01 16:42:46 +01:00
Vadym Markov 2e8b8d83b3 Remove gradient if text is empty 2016-02-01 16:38:59 +01:00
Vadym Markov 44dde5db10 Use LightboxConfig everywhere 2016-02-01 16:25:16 +01:00
Vadym Markov 3d783a7cd1 Remove gradient view functions from public API 2016-02-01 16:01:02 +01:00
Vadym Markov fd98192516 Non publis transition 2016-02-01 15:58:20 +01:00
Vadym Markov 15287809aa Back config 2016-02-01 15:57:20 +01:00
Ramon Gilabert 976df91288 Merge pull request #63 from hyperoslo/feature/empty-init
Feature: set images
2016-02-01 15:40:42 +01:00
Vadym Markov 28c8d37588 Add image configuration method 2016-02-01 14:14:41 +01:00
Vadym Markov b15fc10a53 Add a setter for images 2016-02-01 14:03:03 +01:00
Christoffer Winterkvist a64d12bfcd Merge pull request #62 from hyperoslo/rfactor/config
Remove config in favour of public views.
2016-02-01 13:04:50 +01:00
Vadym Markov 74a000d632 Fix demo 2016-02-01 12:51:03 +01:00
Vadym Markov 947c49008a Rename to LightboxImageLoader 2016-02-01 12:49:01 +01:00
Vadym Markov 764f2e3bd4 Set public when it's needed 2016-02-01 12:48:25 +01:00
Vadym Markov 07231ff480 Remove model 2016-02-01 12:38:44 +01:00
Vadym Markov 70167b93c2 Move info label out of config 2016-02-01 12:31:31 +01:00
Vadym Markov 133ca2db71 Move delete button from config 2016-02-01 12:27:14 +01:00
Vadym Markov d68fa03a90 Move page indicator config 2016-02-01 12:22:01 +01:00
Vadym Markov c144d329e3 Move close button 2016-02-01 12:17:09 +01:00
Vadym Markov 29cd3b8156 Remove zoom scale 2016-02-01 09:45:44 +01:00
Vadym Markov 92ae29af6b Simplify config 2016-02-01 09:43:45 +01:00
Ramon Gilabert de0aa6399a Merge pull request #61 from hyperoslo/refactor/lightbox-image
Refactor Lightbox image
2016-01-31 19:12:23 +01:00
Christoffer Winterkvist 4bfdc39619 Make properties public 2016-01-31 19:06:04 +01:00
Christoffer Winterkvist 5ecb642592 Configure Travis 2016-01-31 19:05:57 +01:00
Ramon Gilabert 217977b4d0 Merge pull request #60 from hyperoslo/fix/dimiss-delegate
Call dismissalDelegate in finishInteractiveTransition
2016-01-31 15:47:05 +01:00
Christoffer Winterkvist e9f1178a41 Call dismissalDelegate in finishInteractiveTransition 2016-01-31 15:45:35 +01:00
Vadym Markov 30c9097671 Merge pull request #59 from hyperoslo/fix/typo-in-delegate-method
Fix typo in delegate method
2016-01-31 15:15:16 +01:00
Christoffer Winterkvist f22fa5fd12 Fix typo in delegate method 2016-01-31 15:14:00 +01:00
Christoffer Winterkvist d98e49b619 Merge pull request #47 from hyperoslo/new-implementation
New implementation request
2016-01-31 14:53:42 +01:00
Vadym Markov aa23e5eae5 Merge pull request #58 from hyperoslo/improve/rotation
Improve rotation
2016-01-31 14:45:21 +01:00
Christoffer Winterkvist f1797e4aa0 Use animateAlongsideTransition when rotating 2016-01-31 14:36:23 +01:00
Christoffer Winterkvist 3e04ad1ef1 Add autoresizingMask to demo view controller 2016-01-31 14:36:05 +01:00
Vadym Markov 0d4bb14d7e Merge pull request #56 from hyperoslo/feature/dynamic-background
Feature dynamic background
2016-01-31 14:09:40 +01:00
Christoffer Winterkvist db24073a03 Set dynamicBackground to true in demo 2016-01-31 14:00:52 +01:00
Christoffer Winterkvist 9c8f008c9a Change backgroundView image when currentPage changes 2016-01-31 14:00:38 +01:00
Christoffer Winterkvist 4a4d40194f Add dynamicBackground property setter 2016-01-31 14:00:24 +01:00
Christoffer Winterkvist e069779449 Add backgroundView 2016-01-31 14:00:11 +01:00
Christoffer Winterkvist f6bad9afe7 Add effectView 2016-01-31 14:00:05 +01:00
Christoffer Winterkvist 327f48b380 Merge pull request #54 from hyperoslo/fix/correct-accorting-to-comments
Minor fixes
2016-01-30 09:45:05 +01:00
Vadym Markov 4d3407f366 Fix alpha 2016-01-30 08:38:38 +01:00
Vadym Markov e7c511644f Use forEach 2016-01-30 08:38:25 +01:00
Vadym Markov b0f99a8529 Use Sugar 2016-01-30 08:38:07 +01:00
Vadym Markov 7e9a7aae75 Unowned self 2016-01-30 08:18:37 +01:00
Vadym Markov b8682ba8ff Merge pull request #53 from hyperoslo/improve/goto-page-in-initialiser
Add startIndex to init method
2016-01-30 08:13:48 +01:00
Christoffer Winterkvist 3d3f7c36c2 Add startIndex to init method 2016-01-29 22:00:12 +01:00
Christoffer Winterkvist c8b046d3c1 Merge pull request #52 from hyperoslo/feature/text-description
Text description feature
2016-01-29 21:36:59 +01:00
Vadym Markov 151aa54e41 Fix text update 2016-01-29 20:47:07 +01:00
Vadym Markov 7fa25f1b8a Update demo 2016-01-29 20:46:57 +01:00
Vadym Markov 57874700bc Implement lightbox image view model 2016-01-29 20:42:42 +01:00
Vadym Markov 0abd6b7eee Add functionality to hide overlay on tap 2016-01-29 20:24:06 +01:00
Vadym Markov 6a06b0f504 Hide delete button on expand 2016-01-29 20:10:39 +01:00
Vadym Markov cbbb2b1553 Fix text height 2016-01-29 20:05:49 +01:00
Vadym Markov f806688547 Update info label logic 2016-01-29 19:59:07 +01:00
Vadym Markov ba60f3eaf3 Fix gradient colors 2016-01-29 12:58:50 +01:00
Vadym Markov 6065273c22 Refactor gradient layers 2016-01-29 12:02:21 +01:00
Vadym Markov 50e1ed3b3a Fix delegates 2016-01-29 11:38:25 +01:00
Vadym Markov bf7dbe02b5 Handle footer view delegate 2016-01-29 11:23:54 +01:00
Vadym Markov fbaa24860a Add footer view delegate 2016-01-29 11:19:52 +01:00
Vadym Markov c7d52ad61f Add info label delegate 2016-01-29 11:16:11 +01:00
Vadym Markov 6ef8b11817 Refactor getters and setters 2016-01-29 10:48:15 +01:00
Vadym Markov 46018422a4 Refactor layout code 2016-01-29 10:46:12 +01:00
Vadym Markov 8f750a4501 Fix transition 2016-01-29 09:43:15 +01:00
Vadym Markov 996b519a27 Layout configurable 2016-01-29 09:42:04 +01:00
Vadym Markov f0ef356066 Setup footer view layout 2016-01-29 09:37:12 +01:00
Vadym Markov 9990486cf9 Move buttons to header view 2016-01-29 09:28:21 +01:00
Vadym Markov 73c34d36d7 Use footer view 2016-01-29 09:10:29 +01:00
Vadym Markov 6e430013ee Refactor code to use LightboxModel 2016-01-28 23:07:38 +01:00
Vadym Markov f3e7c36599 Fix info label 2016-01-28 22:27:49 +01:00
Vadym Markov bcdaf4c013 Add read more color to the config 2016-01-28 21:12:04 +01:00
Vadym Markov 27eb4f08cf Move views to a folder 2016-01-28 21:06:10 +01:00
Vadym Markov 20dc66f5a8 Update podspec 2016-01-28 21:05:55 +01:00
Vadym Markov 247fbcbd37 Add carthage folder to .gitignore 2016-01-28 21:05:37 +01:00
Vadym Markov 2abe24b17b Add carthage dependencies 2016-01-28 21:04:42 +01:00
Vadym Markov 138a9de748 Add info label configuration 2016-01-28 20:51:18 +01:00
Vadym Markov 5f1bc2a3ef Add guards 2016-01-28 20:42:40 +01:00
Vadym Markov 7e160a2382 Add ellipsis to config 2016-01-28 20:41:06 +01:00
Vadym Markov c24e4b3dbe Implement info label 2016-01-28 20:40:41 +01:00
Ramon Gilabert 4b699d70f5 Merge pull request #51 from hyperoslo/feature/double-tap-zoom
Zoom on double tap
2016-01-27 15:07:38 +01:00
Vadym Markov 02376b6313 Fix content size 2016-01-27 15:06:01 +01:00
Vadym Markov 1c8dddfa65 Handle remote images 2016-01-27 14:50:43 +01:00
Vadym Markov 6f098603fe Implement animations to show or hide controls 2016-01-27 14:44:34 +01:00
Vadym Markov 7a190be28d Implement page view delegate 2016-01-27 14:31:23 +01:00
Vadym Markov 0f2ea3673a Add page view delegate 2016-01-27 14:26:15 +01:00
Vadym Markov 2b0f12f581 Refactor code 2016-01-27 14:23:28 +01:00
Vadym Markov 3312be7a70 Add double tap recognizer 2016-01-27 14:19:09 +01:00
Ramon Gilabert 49b370f4a5 Merge pull request #50 from hyperoslo/improve/dismissal
Use velocity when calculating animation time
2016-01-27 13:18:55 +01:00
Christoffer Winterkvist 68d5cff2b4 Use velocity when calculating animation time 2016-01-27 13:13:40 +01:00
Christoffer Winterkvist 7b124968bd Merge pull request #49 from hyperoslo/feature/spacing
Spacing between pages
2016-01-27 12:57:43 +01:00
Vadym Markov f18a0d87e2 Add screen bounds var 2016-01-27 12:46:25 +01:00
Vadym Markov 2c94be7958 Use spacing 2016-01-27 12:44:13 +01:00
Christoffer Winterkvist 4aec366007 Merge pull request #48 from hyperoslo/feature/rotation
Rotation feature
2016-01-27 10:09:43 +01:00
Vadym Markov 268ba7a845 Fix framework project 2016-01-27 09:20:55 +01:00
Vadym Markov 0f1e5bed8a Refactor...refactor...refactor 2016-01-27 09:18:14 +01:00
Vadym Markov 9901ef2031 Implement delete button functionality 2016-01-27 00:00:37 +01:00
Vadym Markov 9b26d1ae88 Refactor code again 2016-01-26 22:33:06 +01:00
Vadym Markov 8505cdd8dc Set frames 2016-01-26 21:58:23 +01:00
Vadym Markov f7c8801958 Add URL init 2016-01-26 21:10:25 +01:00
Vadym Markov 18fa934091 Fix transition 2016-01-26 20:50:24 +01:00
Vadym Markov d2fcfe83e9 Add buttons and page fields 2016-01-26 20:50:19 +01:00
Vadym Markov 3d34271eca Use old config 2016-01-26 20:50:02 +01:00
Vadym Markov 1aff585870 Add marks 2016-01-26 16:38:36 +01:00
Vadym Markov c2ac20cac5 Remove breaks from switch 2016-01-26 16:36:26 +01:00
Vadym Markov 7e1ea31e87 Refactor namings 2016-01-26 16:35:53 +01:00
Vadym Markov 2c24e1e9e0 Remove print 2016-01-25 14:12:04 +01:00
Vadym Markov 020df1ef9c Rename classes 2016-01-25 14:11:45 +01:00
Vadym Markov ba5edcf2c0 Set page views frame 2016-01-25 13:52:25 +01:00
Vadym Markov f6fb1bdc44 Handle rotation in controller 2016-01-25 13:52:12 +01:00
Vadym Markov b9fbaa95df Pod update 2016-01-25 13:51:46 +01:00
Vadym Markov 8bf2ea3a3c Support multiple rotations in Demo project 2016-01-25 13:51:33 +01:00
Ramon Gilabert 9f31ca056a Removes the old demo 2016-01-12 13:43:07 +01:00
Ramon Gilabert bda3e3b87f Adds some more transition code 2016-01-12 13:36:27 +01:00
Ramon Gilabert 9607b24c34 Hides the buttons now 2016-01-12 13:02:53 +01:00
Ramon Gilabert c623ba869d Improves the transition 2016-01-12 11:37:15 +01:00
Ramon Gilabert b2e9da3dbd Fixes the transition 2016-01-12 11:33:24 +01:00
Ramon Gilabert f60deafe0e Adds both ways 2016-01-12 10:37:58 +01:00
Ramon Gilabert 87cbe6b48c Reindentation 2016-01-12 10:29:53 +01:00
Ramon Gilabert 0e7189ae17 Adds some code 2016-01-12 10:02:01 +01:00
Ramon Gilabert f3895b8eca Adds some methods 2016-01-12 09:49:37 +01:00
Ramon Gilabert 18484ac111 Adds some more transition configuration 2016-01-12 09:37:28 +01:00
Ramon Gilabert 11bd59c5ea Adds the method 2016-01-11 15:45:39 +01:00
Ramon Gilabert bc9689125b Adds the gesture recognizer 2016-01-11 15:30:14 +01:00
Ramon Gilabert 495fc0aab4 Adds the different mandatory methods 2016-01-11 15:26:48 +01:00
Ramon Gilabert c6044cecfe Done the zooming 2016-01-11 14:48:40 +01:00
Ramon Gilabert 940b44f14f Removes the controller idea 2016-01-11 14:45:38 +01:00
Ramon Gilabert 75ad50d74a Adds some information 2016-01-11 14:43:34 +01:00
Ramon Gilabert 8eb367b662 Adds the animation for the slideshow 2016-01-11 13:34:17 +01:00
Ramon Gilabert b7a89b80f4 Adds the Lightbox configuration 2016-01-11 13:24:13 +01:00
Ramon Gilabert 27d58fdced Adds the LightboxTransition 2016-01-11 13:22:32 +01:00
Ramon Gilabert 647ab2f558 Adds all the images right away 2016-01-11 12:22:23 +01:00
Ramon Gilabert 9fd3421998 Adds some configuration for the scrollView 2016-01-11 11:28:30 +01:00
Ramon Gilabert 23c1e8dadf Adds some configuration 2016-01-11 11:21:51 +01:00
Ramon Gilabert 1f1209983f Adds image controllers 2016-01-11 11:08:48 +01:00
Ramon Gilabert 6946a9941e Adds information 2016-01-11 11:01:07 +01:00
Ramon Gilabert fac4325d51 Adds the code to add the images 2016-01-11 10:55:01 +01:00
Ramon Gilabert 8a2f229c53 Adds more information 2016-01-11 10:48:00 +01:00
Ramon Gilabert 8edf8a70fa Adds the first LightboxController class 2016-01-11 10:42:33 +01:00
Ramon Gilabert d181b28e91 Deletes all the files 2016-01-11 10:41:54 +01:00
Ramon Gilabert 270f4e887f Adds the button 2016-01-11 10:35:30 +01:00
Ramon Gilabert 49766f0833 Merge remote-tracking branch 'origin/master' into new-implementation 2016-01-11 10:18:30 +01:00
Ramon Gilabert 56664f0b58 Adds the podfile 2016-01-11 09:53:07 +01:00
Ramon Gilabert a259b35826 Adds the files for the example 2016-01-11 09:50:07 +01:00
60 changed files with 2223 additions and 1741 deletions
+3
View File
@@ -28,3 +28,6 @@ DerivedData
# CocoaPods
Pods
# Carthage
Carthage
-4
View File
@@ -1,4 +0,0 @@
ci_service: travis_ci
coverage_service: coveralls
xcodeproj: Tests/Tests.xcodeproj
source_directory: Source
+47
View File
@@ -0,0 +1,47 @@
opt_in_rules: # some rules are only opt-in
- empty_count
# Find all the available rules by running:
# swiftlint rules
included: # paths to include during linting. `--path` is ignored if present.
- Source
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 200
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 500
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 3 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
variable_name:
min_length: # only min_length
error: 2 # only error
excluded: # excluded via string array
- x
- y
- id
- URL
- GlobalAPIKey
- i
- lb
- rb
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle)
-12
View File
@@ -1,12 +0,0 @@
language: objective-c
cache: cocoapods
before_install: gem install cocoapods obcd slather -N
# Use when you don't have third party dependencies
script: xctool -project Pod/Pod.xcodeproj -scheme Tests -sdk iphonesimulator build test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES clean test
# Use when you have third party dependencies (CocoaPods generates a workspace)
# podfile: Pod/Podfile
# script: xctool -workspace Pod/Pod.xcworkspace -scheme Tests -sdk iphonesimulator build test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES clean test
after_success: slather
+2
View File
@@ -0,0 +1,2 @@
github "hyperoslo/Imaginary" ~> 4.3
github "hyperoslo/Cache" ~> 5.3
+2
View File
@@ -0,0 +1,2 @@
github "hyperoslo/Cache" "5.3.0"
github "hyperoslo/Imaginary" "4.3.1"
@@ -1,367 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0C9AD201C04B66C0716FF73F /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8728C35FD683AF84D7CC1A5D /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
298CC3D01B5685B300BA502F /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 298CC3CF1B5685B300BA502F /* MainViewController.swift */; };
D5C0BDFB1B42CCBC009E6446 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */; };
D5C0BE021B42CCBC009E6446 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE011B42CCBC009E6446 /* Images.xcassets */; };
D5C0BE051B42CCBC009E6446 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */; };
D5C0BE1B1B42CF62009E6446 /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE1A1B42CF62009E6446 /* Podfile */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
298CC3CF1B5685B300BA502F /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
8728C35FD683AF84D7CC1A5D /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LightboxDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
D5C0BDF91B42CCBC009E6446 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D5C0BE011B42CCBC009E6446 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
D5C0BE041B42CCBC009E6446 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
D5C0BE1A1B42CF62009E6446 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D5C0BDF21B42CCBC009E6446 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C9AD201C04B66C0716FF73F /* Pods.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0A38C4CB9ED946C3E5379ACD /* Frameworks */ = {
isa = PBXGroup;
children = (
8728C35FD683AF84D7CC1A5D /* Pods.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7CC838A3597315C7F8990A20 /* Pods */ = {
isa = PBXGroup;
children = (
23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */,
76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
D5C0BDEC1B42CCBC009E6446 = {
isa = PBXGroup;
children = (
D5C0BE1A1B42CF62009E6446 /* Podfile */,
D5C0BDF71B42CCBC009E6446 /* LightboxDemo */,
D5C0BDF61B42CCBC009E6446 /* Products */,
7CC838A3597315C7F8990A20 /* Pods */,
0A38C4CB9ED946C3E5379ACD /* Frameworks */,
);
sourceTree = "<group>";
};
D5C0BDF61B42CCBC009E6446 /* Products */ = {
isa = PBXGroup;
children = (
D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
D5C0BDF71B42CCBC009E6446 /* LightboxDemo */ = {
isa = PBXGroup;
children = (
D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */,
298CC3CF1B5685B300BA502F /* MainViewController.swift */,
D5C0BE011B42CCBC009E6446 /* Images.xcassets */,
D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */,
D5C0BDF81B42CCBC009E6446 /* Supporting Files */,
);
path = LightboxDemo;
sourceTree = "<group>";
};
D5C0BDF81B42CCBC009E6446 /* Supporting Files */ = {
isa = PBXGroup;
children = (
D5C0BDF91B42CCBC009E6446 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
D5C0BDF41B42CCBC009E6446 /* LightboxDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = D5C0BE141B42CCBC009E6446 /* Build configuration list for PBXNativeTarget "LightboxDemo" */;
buildPhases = (
33BD1BD41EDB7355D8EEE7B2 /* Check Pods Manifest.lock */,
D5C0BDF11B42CCBC009E6446 /* Sources */,
D5C0BDF21B42CCBC009E6446 /* Frameworks */,
D5C0BDF31B42CCBC009E6446 /* Resources */,
BC0AD25D0149B45E9C4A9A25 /* Embed Pods Frameworks */,
856840040ECE7A9C6538CCF0 /* Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = LightboxDemo;
productName = LightboxDemo;
productReference = D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D5C0BDED1B42CCBC009E6446 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = Hyper;
TargetAttributes = {
D5C0BDF41B42CCBC009E6446 = {
CreatedOnToolsVersion = 6.3.2;
};
};
};
buildConfigurationList = D5C0BDF01B42CCBC009E6446 /* Build configuration list for PBXProject "LightboxDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D5C0BDEC1B42CCBC009E6446;
productRefGroup = D5C0BDF61B42CCBC009E6446 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D5C0BDF41B42CCBC009E6446 /* LightboxDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D5C0BDF31B42CCBC009E6446 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D5C0BE1B1B42CF62009E6446 /* Podfile in Resources */,
D5C0BE051B42CCBC009E6446 /* LaunchScreen.xib in Resources */,
D5C0BE021B42CCBC009E6446 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
33BD1BD41EDB7355D8EEE7B2 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
856840040ECE7A9C6538CCF0 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
BC0AD25D0149B45E9C4A9A25 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D5C0BDF11B42CCBC009E6446 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D5C0BDFB1B42CCBC009E6446 /* AppDelegate.swift in Sources */,
298CC3D01B5685B300BA502F /* MainViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
D5C0BE041B42CCBC009E6446 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
D5C0BE121B42CCBC009E6446 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
D5C0BE131B42CCBC009E6446 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D5C0BE151B42CCBC009E6446 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LightboxDemo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
D5C0BE161B42CCBC009E6446 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LightboxDemo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D5C0BDF01B42CCBC009E6446 /* Build configuration list for PBXProject "LightboxDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D5C0BE121B42CCBC009E6446 /* Debug */,
D5C0BE131B42CCBC009E6446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D5C0BE141B42CCBC009E6446 /* Build configuration list for PBXNativeTarget "LightboxDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D5C0BE151B42CCBC009E6446 /* Debug */,
D5C0BE161B42CCBC009E6446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D5C0BDED1B42CCBC009E6446 /* Project object */;
}
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:LightboxDemo.xcodeproj">
</FileRef>
</Workspace>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:LightboxDemo.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
@@ -1,20 +0,0 @@
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var window: UIWindow? = {
let window = UIWindow(frame: UIScreen.mainScreen().bounds)
return window
}()
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window!.rootViewController = MainViewController()
window!.backgroundColor = UIColor.whiteColor()
window!.makeKeyAndVisible()
return true
}
}
@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Hyper. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LightboxDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
@@ -1,38 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

@@ -1,40 +0,0 @@
import UIKit
import Lightbox
class MainViewController: UIViewController {
lazy var galleryButton: UIButton = { [unowned self] in
let button = UIButton()
button.setTitle("Show the gallery", forState: .Normal)
button.setTitleColor(UIColor(red:0.98, green:0.18, blue:0.36, alpha:1), forState: .Normal)
button.titleLabel!.font = UIFont(name: "AvenirNextCondensed-DemiBold", size: 24)
button.addTarget(self, action: "galleryButtonDidPress:", forControlEvents: .TouchUpInside)
button.frame = CGRectMake(0, 0,
UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(galleryButton)
}
// MARK: Action handlers
func galleryButtonDidPress(button: UIButton) {
let controller = LightboxController(images: ["photo1", "photo2", "photo3"])
controller.dismissalDelegate = self
presentViewController(controller, animated: true, completion: nil)
}
}
// MARK: Lightbox delegate methods
extension MainViewController : LightboxControllerDismissalDelegate {
func lightboxControllerDidDismiss(controller: LightboxController) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
-6
View File
@@ -1,6 +0,0 @@
platform :ios, '8.0'
use_frameworks!
inhibit_all_warnings!
pod 'Lightbox', path: '../../'
-14
View File
@@ -1,14 +0,0 @@
PODS:
- Lightbox (0.1.0)
DEPENDENCIES:
- Lightbox (from `../../`)
EXTERNAL SOURCES:
Lightbox:
:path: ../../
SPEC CHECKSUMS:
Lightbox: 4f31e0609376469443c9b0df85efe1c737209aa5
COCOAPODS: 0.39.0.beta.4
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

+9 -5
View File
@@ -1,15 +1,19 @@
Pod::Spec.new do |s|
s.name = "Lightbox"
s.summary = "A short description of Lightbox."
s.version = "0.1.0"
s.summary = "A a convenient and easy to use image viewer for your iOS app, packed with all the features you expect"
s.version = "2.4.2"
s.homepage = "https://github.com/hyperoslo/Lightbox"
s.license = 'MIT'
s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" }
s.source = { :git => "https://github.com/hyperoslo/Lightbox.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/hyperoslo'
s.platform = :ios, '8.0'
s.platform = :ios, '9.0'
s.requires_arc = true
s.source_files = 'Source/**/*'
# s.frameworks = 'UIKit', 'MapKit'
# s.dependency 'AFNetworking', '~> 2.3'
s.ios.resource = 'Resources/Lightbox.bundle'
s.frameworks = 'UIKit', 'AVFoundation', 'AVKit'
s.dependency 'Imaginary', '~> 4.3.1'
s.swift_version = '5.0'
end
+324 -26
View File
@@ -7,51 +7,152 @@
objects = {
/* Begin PBXBuildFile section */
D523B0BC1C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */; };
166E3BA920333E04006799C1 /* LightboxImageStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 166E3BA820333E04006799C1 /* LightboxImageStub.swift */; };
44E6A64A2495BFAB00543CF0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E6A6492495BFAB00543CF0 /* AppDelegate.swift */; };
44E6A6532495BFAC00543CF0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 44E6A6522495BFAC00543CF0 /* Assets.xcassets */; };
44E6A6562495BFAC00543CF0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 44E6A6542495BFAC00543CF0 /* LaunchScreen.storyboard */; };
44E6A65C2495BFD400543CF0 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44E6A65B2495BFD400543CF0 /* ViewController.swift */; };
44E6A6652495C0EB00543CF0 /* Lightbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D523B0A91C43AA2A001AD1EC /* Lightbox.framework */; };
44E6A6662495C0EB00543CF0 /* Lightbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D523B0A91C43AA2A001AD1EC /* Lightbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
44E6A66A2495C13F00543CF0 /* Imaginary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2A58F5D1F7943A30064F14E /* Imaginary.framework */; };
44E6A66B2495C13F00543CF0 /* Imaginary.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D2A58F5D1F7943A30064F14E /* Imaginary.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D22006741DFB4D9700E92898 /* Lightbox.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D22006731DFB4D9700E92898 /* Lightbox.bundle */; };
D2258CC4215CD035005A9A1C /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2258CC3215CD035005A9A1C /* Color+Extensions.swift */; };
D2A58F5E1F7943A30064F14E /* Imaginary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2A58F5D1F7943A30064F14E /* Imaginary.framework */; };
D2D71BBC1D54DA77006AB907 /* AssetManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D71BBB1D54DA77006AB907 /* AssetManager.swift */; };
D5026B3C1C5BF3FD003BC1A3 /* LightboxImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */; };
D523B0BD1C43AA8B001AD1EC /* LightboxConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */; };
D523B0BE1C43AA8B001AD1EC /* LightboxController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B71C43AA8A001AD1EC /* LightboxController.swift */; };
D523B0BF1C43AA8B001AD1EC /* LightboxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */; };
D523B0C01C43AA8B001AD1EC /* LightboxTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */; };
D523B0C11C43AA8B001AD1EC /* LightboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */; };
D523B0C21C43AA8B001AD1EC /* LightboxViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */; };
D54DFCBE1C5AAAD600ADEA0E /* InfoLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */; };
D54DFCBF1C5AAAD600ADEA0E /* PageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */; };
D56F15C81E0AB79800F128AF /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */; };
D573A2F01C5B5605006053DD /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2EF1C5B5605006053DD /* HeaderView.swift */; };
D573A2F31C5B5C7B006053DD /* LayoutConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */; };
D573A2F51C5B5CA4006053DD /* LightboxTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */; };
D573A2F71C5B5E55006053DD /* UIView+Gradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */; };
D58A18CB1C5ABF8F000024BB /* FooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58A18CA1C5ABF8F000024BB /* FooterView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
44E6A6672495C0EB00543CF0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D523B0A01C43AA2A001AD1EC /* Project object */;
proxyType = 1;
remoteGlobalIDString = D523B0A81C43AA2A001AD1EC;
remoteInfo = "Lightbox-iOS";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
44E6A6692495C0EB00543CF0 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
44E6A66B2495C13F00543CF0 /* Imaginary.framework in Embed Frameworks */,
44E6A6662495C0EB00543CF0 /* Lightbox.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
166E3BA820333E04006799C1 /* LightboxImageStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightboxImageStub.swift; sourceTree = "<group>"; };
44E6A6472495BFAB00543CF0 /* iOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
44E6A6492495BFAB00543CF0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
44E6A6522495BFAC00543CF0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
44E6A6552495BFAC00543CF0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
44E6A6572495BFAC00543CF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
44E6A65B2495BFD400543CF0 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
D22006731DFB4D9700E92898 /* Lightbox.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Lightbox.bundle; sourceTree = "<group>"; };
D2258CC3215CD035005A9A1C /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = "<group>"; };
D2A58F5D1F7943A30064F14E /* Imaginary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Imaginary.framework; path = Carthage/Build/iOS/Imaginary.framework; sourceTree = "<group>"; };
D2D71BBB1D54DA77006AB907 /* AssetManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetManager.swift; sourceTree = "<group>"; };
D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxImage.swift; sourceTree = "<group>"; };
D523B0A91C43AA2A001AD1EC /* Lightbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Lightbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D523B0AE1C43AA2A001AD1EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CenterCellCollectionViewFlowLayout.swift; sourceTree = "<group>"; };
D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxConfig.swift; sourceTree = "<group>"; };
D523B0B71C43AA8A001AD1EC /* LightboxController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxController.swift; sourceTree = "<group>"; };
D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxDataSource.swift; sourceTree = "<group>"; };
D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxTransition.swift; sourceTree = "<group>"; };
D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxView.swift; sourceTree = "<group>"; };
D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxViewCell.swift; sourceTree = "<group>"; };
D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoLabel.swift; sourceTree = "<group>"; };
D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageView.swift; sourceTree = "<group>"; };
D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = "<group>"; };
D573A2EF1C5B5605006053DD /* HeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutConfigurable.swift; sourceTree = "<group>"; };
D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxTransition.swift; sourceTree = "<group>"; };
D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Gradient.swift"; sourceTree = "<group>"; };
D58A18CA1C5ABF8F000024BB /* FooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
44E6A6442495BFAB00543CF0 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
44E6A66A2495C13F00543CF0 /* Imaginary.framework in Frameworks */,
44E6A6652495C0EB00543CF0 /* Lightbox.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D523B0A51C43AA2A001AD1EC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D2A58F5E1F7943A30064F14E /* Imaginary.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
44E6A6482495BFAB00543CF0 /* iOSDemo */ = {
isa = PBXGroup;
children = (
44E6A6492495BFAB00543CF0 /* AppDelegate.swift */,
44E6A65B2495BFD400543CF0 /* ViewController.swift */,
44E6A6522495BFAC00543CF0 /* Assets.xcassets */,
44E6A6542495BFAC00543CF0 /* LaunchScreen.storyboard */,
44E6A6572495BFAC00543CF0 /* Info.plist */,
);
path = iOSDemo;
sourceTree = "<group>";
};
D22006721DFB4D9700E92898 /* Resources */ = {
isa = PBXGroup;
children = (
D22006731DFB4D9700E92898 /* Lightbox.bundle */,
);
path = Resources;
sourceTree = "<group>";
};
D2A58F5C1F7943A30064F14E /* Frameworks */ = {
isa = PBXGroup;
children = (
D2A58F5D1F7943A30064F14E /* Imaginary.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
D523B09F1C43AA2A001AD1EC = {
isa = PBXGroup;
children = (
D22006721DFB4D9700E92898 /* Resources */,
D523B0B41C43AA8A001AD1EC /* Source */,
D523B0AB1C43AA2A001AD1EC /* Lightbox */,
44E6A6482495BFAB00543CF0 /* iOSDemo */,
D523B0AA1C43AA2A001AD1EC /* Products */,
D2A58F5C1F7943A30064F14E /* Frameworks */,
);
indentWidth = 4;
sourceTree = "<group>";
tabWidth = 4;
};
D523B0AA1C43AA2A001AD1EC /* Products */ = {
isa = PBXGroup;
children = (
D523B0A91C43AA2A001AD1EC /* Lightbox.framework */,
44E6A6472495BFAB00543CF0 /* iOSDemo.app */,
);
name = Products;
sourceTree = "<group>";
@@ -67,17 +168,40 @@
D523B0B41C43AA8A001AD1EC /* Source */ = {
isa = PBXGroup;
children = (
D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */,
D573A2F11C5B5C72006053DD /* Library */,
D54DFCBB1C5AAAD600ADEA0E /* Views */,
D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */,
D523B0B71C43AA8A001AD1EC /* LightboxController.swift */,
D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */,
D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */,
D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */,
D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */,
D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */,
166E3BA820333E04006799C1 /* LightboxImageStub.swift */,
D2D71BBB1D54DA77006AB907 /* AssetManager.swift */,
);
path = Source;
sourceTree = "<group>";
};
D54DFCBB1C5AAAD600ADEA0E /* Views */ = {
isa = PBXGroup;
children = (
D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */,
D573A2EF1C5B5605006053DD /* HeaderView.swift */,
D58A18CA1C5ABF8F000024BB /* FooterView.swift */,
D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */,
D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */,
);
path = Views;
sourceTree = "<group>";
};
D573A2F11C5B5C72006053DD /* Library */ = {
isa = PBXGroup;
children = (
D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */,
D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */,
D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */,
D2258CC3215CD035005A9A1C /* Color+Extensions.swift */,
);
path = Library;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -91,6 +215,25 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
44E6A6462495BFAB00543CF0 /* iOSDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 44E6A6582495BFAC00543CF0 /* Build configuration list for PBXNativeTarget "iOSDemo" */;
buildPhases = (
44E6A6432495BFAB00543CF0 /* Sources */,
44E6A6442495BFAB00543CF0 /* Frameworks */,
44E6A6452495BFAB00543CF0 /* Resources */,
44E6A6692495C0EB00543CF0 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
44E6A6682495C0EB00543CF0 /* PBXTargetDependency */,
);
name = iOSDemo;
productName = iOSDemo;
productReference = 44E6A6472495BFAB00543CF0 /* iOSDemo.app */;
productType = "com.apple.product-type.application";
};
D523B0A81C43AA2A001AD1EC /* Lightbox-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = D523B0B11C43AA2A001AD1EC /* Build configuration list for PBXNativeTarget "Lightbox-iOS" */;
@@ -115,20 +258,27 @@
D523B0A01C43AA2A001AD1EC /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
LastSwiftUpdateCheck = 1150;
LastUpgradeCheck = 1150;
ORGANIZATIONNAME = "Hyper Interaktiv AS";
TargetAttributes = {
44E6A6462495BFAB00543CF0 = {
CreatedOnToolsVersion = 11.5;
ProvisioningStyle = Automatic;
};
D523B0A81C43AA2A001AD1EC = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 1150;
};
};
};
buildConfigurationList = D523B0A31C43AA2A001AD1EC /* Build configuration list for PBXProject "Lightbox" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D523B09F1C43AA2A001AD1EC;
productRefGroup = D523B0AA1C43AA2A001AD1EC /* Products */;
@@ -136,53 +286,166 @@
projectRoot = "";
targets = (
D523B0A81C43AA2A001AD1EC /* Lightbox-iOS */,
44E6A6462495BFAB00543CF0 /* iOSDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
44E6A6452495BFAB00543CF0 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
44E6A6562495BFAC00543CF0 /* LaunchScreen.storyboard in Resources */,
44E6A6532495BFAC00543CF0 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D523B0A71C43AA2A001AD1EC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D22006741DFB4D9700E92898 /* Lightbox.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
44E6A6432495BFAB00543CF0 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
44E6A65C2495BFD400543CF0 /* ViewController.swift in Sources */,
44E6A64A2495BFAB00543CF0 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D523B0A41C43AA2A001AD1EC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D56F15C81E0AB79800F128AF /* LoadingIndicator.swift in Sources */,
D54DFCBF1C5AAAD600ADEA0E /* PageView.swift in Sources */,
D573A2F71C5B5E55006053DD /* UIView+Gradient.swift in Sources */,
D523B0BD1C43AA8B001AD1EC /* LightboxConfig.swift in Sources */,
D523B0C11C43AA8B001AD1EC /* LightboxView.swift in Sources */,
D573A2F31C5B5C7B006053DD /* LayoutConfigurable.swift in Sources */,
D5026B3C1C5BF3FD003BC1A3 /* LightboxImage.swift in Sources */,
D523B0BE1C43AA8B001AD1EC /* LightboxController.swift in Sources */,
D523B0C21C43AA8B001AD1EC /* LightboxViewCell.swift in Sources */,
D523B0BC1C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift in Sources */,
D523B0C01C43AA8B001AD1EC /* LightboxTransition.swift in Sources */,
D523B0BF1C43AA8B001AD1EC /* LightboxDataSource.swift in Sources */,
D54DFCBE1C5AAAD600ADEA0E /* InfoLabel.swift in Sources */,
D58A18CB1C5ABF8F000024BB /* FooterView.swift in Sources */,
D573A2F01C5B5605006053DD /* HeaderView.swift in Sources */,
D573A2F51C5B5CA4006053DD /* LightboxTransition.swift in Sources */,
D2258CC4215CD035005A9A1C /* Color+Extensions.swift in Sources */,
166E3BA920333E04006799C1 /* LightboxImageStub.swift in Sources */,
D2D71BBC1D54DA77006AB907 /* AssetManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
44E6A6682495C0EB00543CF0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D523B0A81C43AA2A001AD1EC /* Lightbox-iOS */;
targetProxy = 44E6A6672495C0EB00543CF0 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
44E6A6542495BFAC00543CF0 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
44E6A6552495BFAC00543CF0 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
44E6A6592495BFAC00543CF0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = iOSDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.5;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.elvisnunez.iOSDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
44E6A65A2495BFAC00543CF0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = iOSDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.5;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.elvisnunez.iOSDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
D523B0AF1C43AA2A001AD1EC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -205,11 +468,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -220,17 +484,28 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -247,9 +522,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
@@ -260,40 +537,61 @@
D523B0B21C43AA2A001AD1EC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Lightbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Lightbox;
PRODUCT_NAME = Lightbox;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
D523B0B31C43AA2A001AD1EC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Lightbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Lightbox;
PRODUCT_NAME = Lightbox;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
44E6A6582495BFAC00543CF0 /* Build configuration list for PBXNativeTarget "iOSDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
44E6A6592495BFAC00543CF0 /* Debug */,
44E6A65A2495BFAC00543CF0 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D523B0A31C43AA2A001AD1EC /* Build configuration list for PBXProject "Lightbox" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "1150"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -15,7 +15,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
@@ -27,10 +27,29 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D229B5E01FC3123F00F04123"
BuildableName = "Lightbox-iOS-Tests.xctest"
BlueprintName = "Lightbox-iOS-Tests"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -46,13 +65,11 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -64,7 +81,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
+22
View File
@@ -0,0 +1,22 @@
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "Lightbox",
products: [
.library(
name: "Lightbox",
targets: ["Lightbox"]),
],
dependencies: [
.package(url: "https://github.com/hyperoslo/Imaginary", .branch("master"))
],
targets: [
.target(
name: "Lightbox",
dependencies: ["Imaginary"],
path: "Source"
)
],
swiftLanguageVersions: [.v5]
)
+172 -4
View File
@@ -1,14 +1,165 @@
# Lightbox
[![CI Status](http://img.shields.io/travis/hyperoslo/Lightbox.svg?style=flat)](https://travis-ci.org/hyperoslo/Lightbox)
[![Version](https://img.shields.io/cocoapods/v/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
[![CI Status](https://circleci.com/gh/hyperoslo/Lightbox.png)](https://circleci.com/gh/hyperoslo/Lightbox)
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
[![Platform](https://img.shields.io/cocoapods/p/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
![Swift](https://img.shields.io/badge/%20in-swift%204.0-orange.svg)
<img src="https://raw.githubusercontent.com/hyperoslo/Lightbox/master/Images/Icon.png" alt="Lightbox Icon" align="right" />
**Lightbox** is a convenient and easy to use image viewer for your iOS app,
packed with all the features you expect:
- [x] Paginated image slideshow.
- [x] Video support.
- [x] Double-tap to zoom.
- [x] Image caption.
- [x] Dynamic background based on [Hue](https://github.com/hyperoslo/Hue)
- [x] Remote image loading and caching based on [Imaginary](https://github.com/hyperoslo/Imaginary)
- [x] Interactive transition animations.
- [x] Powerful configuration.
- [x] [Live Demo](https://appetize.io/app/wfgwc2uvg82m9pzbt17p4rrgh4?device=iphone5s&scale=75&orientation=portrait&osVersion=9.3)
<div align="center">
<img src="Images/demo.png" height="500">
<img src="Images/demo2.png" height="500">
</div>
## Table of Contents
* [Usage](#usage)
* [Controller](#controller)
* [Delegates](#delegates)
* [Image loading](#image-loading)
* [Video](#video)
* [Configuration](#configuration)
* [Installation](#installation)
* [Author](#author)
* [Contributing](#contributing)
* [License](#license)
## Usage
### Controller
To start your slideshow just instantiate `LightboxController`, set needed
delegates and present it:
```swift
<API>
// Create an array of images.
let images = [
LightboxImage(imageURL: URL(string: "https://cdn.arstechnica.net/2011/10/05/iphone4s_sample_apple-4e8c706-intro.jpg")!),
LightboxImage(
image: UIImage(named: "photo1")!,
text: "This is an example of a remote image loaded from URL"
),
LightboxImage(
image: UIImage(named: "photo2")!,
text: "",
videoURL: URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
),
LightboxImage(
image: UIImage(named: "photo3")!,
text: "This is an example of a local image."
)
]
// Create an instance of LightboxController.
let controller = LightboxController(images: images)
// Set delegates.
controller.pageDelegate = self
controller.dismissalDelegate = self
// Use dynamic background.
controller.dynamicBackground = true
// Present your controller.
present(controller, animated: true, completion: nil)
```
### Delegates
Use `LightboxControllerPageDelegate` if you want to be notified about page
navigation changes.
```swift
extension ViewController: LightboxControllerPageDelegate {
func lightboxController(_ controller: LightboxController, didMoveToPage page: Int) {
print(page)
}
}
```
Use `LightboxControllerDismissalDelegate` to be notified when controller is
about to be dismissed. Please note that `LightboxController` dismisses itself
if it was presented initially.
```swift
extension ViewController: LightboxControllerDismissalDelegate: class {
func lightboxControllerWillDismiss(_ controller: LightboxController) {
// ...
}
}
```
### Image loading
By default images are loaded using [Imaginary](https://github.com/hyperoslo/Imaginary) for reliable loading and caching. But it's easy to change this behavior using **LightboxConfig**
```swift
LightboxConfig.loadImage = {
imageView, URL, completion in
// Custom image loading
}
```
### Video
**Lightbox** can show and plays video using default `AVPlayerViewController`. Showning video by using `videoURL`:
```swift
LightboxImage(
image: UIImage(named: "photo2")!,
text: "",
videoURL: NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
)
```
Override video handling if needed:
```swift
LightboxConfig.handleVideo = { from, videoURL in
// Custom video handling
let videoController = AVPlayerViewController()
videoController.player = AVPlayer(url: videoURL)
from.present(videoController, animated: true) {
videoController.player?.play()
}
}
```
### Configuration
Configure text, colors, fonts of UI elements by overriding the static
variables in the **Lightbox** [configuration](https://github.com/hyperoslo/Lightbox/blob/master/Source/LightboxConfig.swift) struct. As an example:
```swift
LightboxConfig.CloseButton.image = UIImage(named: ImageList.Lightbox.closeButton)
LightboxConfig.CloseButton.textAttributes = TextAttributes.Lightbox.closeButton
LightboxConfig.CloseButton.text = "Finish"
LightboxConfig.DeleteButton.image = UIImage(named: ImageList.Lightbox.deleteButton)
LightboxConfig.DeleteButton.textAttributes = TextAttributes.Lightbox.deleteButton
LightboxConfig.DeleteButton.text = "Delete"
LightboxConfig.InfoLabel.ellipsisText = "Show more"
```
## Installation
@@ -20,10 +171,27 @@ it, simply add the following line to your Podfile:
pod 'Lightbox'
```
In order to quickly try the demo project of a **Lightbox** just run
`pod try Lightbox` in your terminal.
**Lightbox** is also available through [Carthage](https://github.com/Carthage/Carthage).
To install just write into your Cartfile:
```ruby
github "hyperoslo/Lightbox"
```
To install **Lightbox** manually just download and drop `Sources` and
`Images` folders in your project.
## Author
Hyper Interaktiv AS, ios@hyper.no
## Contributing
We would love you to contribute to **Lightbox**, check the [CONTRIBUTING](https://github.com/hyperoslo/Lightbox/blob/master/CONTRIBUTING.md) file for more info.
## License
**Lightbox** is available under the MIT license. See the LICENSE file for more info.
**Lightbox** is available under the MIT license. See the [LICENSE](https://github.com/hyperoslo/Lightbox/blob/master/LICENSE.md) file for more info.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

+10
View File
@@ -0,0 +1,10 @@
import UIKit
/// Used to load assets from Lightbox bundle
class AssetManager {
static func image(_ named: String) -> UIImage? {
let bundle = Bundle(for: AssetManager.self)
return UIImage(named: "Lightbox.bundle/\(named)", in: bundle, compatibleWith: nil)
}
}
@@ -1,43 +0,0 @@
import UIKit
class CenterCellCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
if let collectionView = self.collectionView {
let collectionViewBounds = collectionView.bounds
let halfWidth = collectionViewBounds.size.width / 2
let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidth
if let attributesForVisibleCells = layoutAttributesForElementsInRect(collectionViewBounds) {
var candidateAttributes : UICollectionViewLayoutAttributes?
for attributes in attributesForVisibleCells.filter({
$0.representedElementCategory == UICollectionElementCategory.Cell}) {
if let candAttrs = candidateAttributes {
let a = attributes.center.x - proposedContentOffsetCenterX
let b = candAttrs.center.x - proposedContentOffsetCenterX
if velocity.x < 0 {
continue
} else if velocity.x > 0 {
candidateAttributes = attributes
} else if fabsf(Float(a)) < fabsf(Float(b)) {
candidateAttributes = attributes
}
} else { // First time in the loop
candidateAttributes = attributes
continue
}
}
return CGPoint(
x: candidateAttributes!.center.x - halfWidth,
y: proposedContentOffset.y)
}
}
return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
}
}
+27
View File
@@ -0,0 +1,27 @@
import UIKit
internal extension UIColor {
/// Constructing color from hex string
///
/// - Parameter hex: A hex string, can either contain # or not
convenience init(hex string: String) {
var hex = string.hasPrefix("#")
? String(string.dropFirst())
: string
guard hex.count == 3 || hex.count == 6
else {
self.init(white: 1.0, alpha: 0.0)
return
}
if hex.count == 3 {
for (index, char) in hex.enumerated() {
hex.insert(char, at: hex.index(hex.startIndex, offsetBy: index * 2))
}
}
self.init(
red: CGFloat((Int(hex, radix: 16)! >> 16) & 0xFF) / 255.0,
green: CGFloat((Int(hex, radix: 16)! >> 8) & 0xFF) / 255.0,
blue: CGFloat((Int(hex, radix: 16)!) & 0xFF) / 255.0, alpha: 1.0)
}
}
+4
View File
@@ -0,0 +1,4 @@
protocol LayoutConfigurable: class {
func configureLayout()
}
+173
View File
@@ -0,0 +1,173 @@
import UIKit
class LightboxTransition: UIPercentDrivenInteractiveTransition {
lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
let gesture = UIPanGestureRecognizer()
gesture.addTarget(self, action: #selector(handlePanGesture(_:)))
gesture.delegate = self
return gesture
}()
var interactive = false
var dismissing = false
var initialOrigin = CGPoint(x: 0, y: 0)
var scrollView: UIScrollView? {
didSet {
guard let scrollView = scrollView else { return }
scrollView.addGestureRecognizer(panGestureRecognizer)
}
}
weak var lightboxController: LightboxController?
// MARK: - Transition
func transition(_ show: Bool) {
guard let controller = lightboxController else { return }
if interactive {
controller.view.backgroundColor = UIColor.black.withAlphaComponent(show ? 1 : 0)
} else {
controller.view.alpha = show ? 1 : 0
}
}
// MARK: - Pan gesture recognizer
@objc func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: scrollView)
let percentage = abs(translation.y) / UIScreen.main.bounds.height / 1.5
let velocity = gesture.velocity(in: scrollView)
switch gesture.state {
case .began:
interactive = true
lightboxController?.presented = false
lightboxController?.dismiss(animated: true, completion: nil)
if let origin = scrollView?.frame.origin { initialOrigin = origin }
case .changed:
update(percentage)
scrollView?.frame.origin.y = initialOrigin.y + translation.y
case .ended, .cancelled:
var time = translation.y * 3 / abs(velocity.y)
if time > 1 { time = 0.7 }
interactive = false
lightboxController?.presented = true
if percentage > 0.1 {
finish()
guard let controller = lightboxController else { return }
controller.headerView.alpha = 0
controller.footerView.alpha = 0
UIView.animate(withDuration: TimeInterval(time), delay: 0, options: [.allowUserInteraction], animations: {
self.scrollView?.frame.origin.y = translation.y * 3
controller.view.alpha = 0
controller.view.backgroundColor = UIColor.black.withAlphaComponent(0)
}, completion: { _ in })
} else {
cancel()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.035) {
UIView.animate(withDuration: 0.35, animations: {
self.scrollView?.frame.origin = self.initialOrigin
})
}
}
default: break
}
}
override func finish() {
super.finish()
guard let lightboxController = lightboxController else { return }
lightboxController.dismissalDelegate?.lightboxControllerWillDismiss(lightboxController)
}
}
// MARK: - UIViewControllerAnimatedTransitioning
extension LightboxTransition: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
guard let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from),
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)
else { return }
let firstView = dismissing ? toView : fromView
let secondView = dismissing ? fromView : toView
if !dismissing { transition(false) }
container.addSubview(firstView)
container.addSubview(secondView)
toView.frame = container.bounds
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, animations: {
self.transition(!self.dismissing)
}, completion: { _ in
transitionContext.transitionWasCancelled
? transitionContext.completeTransition(false)
: transitionContext.completeTransition(true)
})
}
}
// MARK: - UIViewControllerTransitioningDelegate
extension LightboxTransition: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
dismissing = true
return self
}
func animationController(forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
dismissing = false
return self
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
}
// MARK: - UIGestureRecognizerDelegate
extension LightboxTransition: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
var result = false
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translation(in: gestureRecognizer.view)
if abs(translation.x) < abs(translation.y) {
result = true
}
}
return result
}
}
+30
View File
@@ -0,0 +1,30 @@
import UIKit
extension UIView {
@discardableResult func addGradientLayer(_ colors: [UIColor]) -> CAGradientLayer {
if let gradientLayer = gradientLayer { return gradientLayer }
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = colors.map { $0.cgColor }
layer.insertSublayer(gradient, at: 0)
return gradient
}
func removeGradientLayer() -> CAGradientLayer? {
gradientLayer?.removeFromSuperlayer()
return gradientLayer
}
func resizeGradientLayer() {
gradientLayer?.frame = bounds
}
fileprivate var gradientLayer: CAGradientLayer? {
return layer.sublayers?.first as? CAGradientLayer
}
}
+79 -60
View File
@@ -1,90 +1,109 @@
import UIKit
import AVKit
import AVFoundation
import Imaginary
class LightboxConfig {
public class LightboxConfig {
/// Whether to show status bar while Lightbox is presented
public static var hideStatusBar = true
var config = Config()
/// Provide a closure to handle selected video
public static var handleVideo: (_ from: UIViewController, _ videoURL: URL) -> Void = { from, videoURL in
let videoController = AVPlayerViewController()
videoController.player = AVPlayer(url: videoURL)
static let sharedInstance = LightboxConfig()
}
from.present(videoController, animated: true) {
videoController.player?.play()
}
}
public struct Config {
/// How to load image onto UIImageView
public static var loadImage: (UIImageView, URL, ((UIImage?) -> Void)?) -> Void = { (imageView, imageURL, completion) in
public var hideStatusBar = true
public var backgroundColor = UIColor.clearColor()
public var pageIndicator = PageIndicator()
public var closeButton = CloseButton()
public var deleteButton = DeleteButton()
public var zoom = Zoom()
public var remoteImages = false
public var spacing: CGFloat = 20
public typealias LoadImageCompletion = (error: NSError?) -> Void
public var loadImage: (imageView: UIImageView, URL: NSURL, completion: LoadImageCompletion?) -> Void = {
imageView, URL, completion in
let imageRequest: NSURLRequest = NSURLRequest(URL: URL)
NSURLConnection.sendAsynchronousRequest(imageRequest,
queue: NSOperationQueue.mainQueue(),
completionHandler: { response, data, error in
if let data = data, image = UIImage(data: data) {
imageView.image = image
}
completion?(error: error)
// Use Imaginary by default
imageView.setImage(url: imageURL, placeholder: nil, completion: { result in
switch result {
case .value(let image):
completion?(image)
case .error:
completion?(nil)
}
})
}
public init() { }
/// Indicator is used to show while image is being fetched
public static var makeLoadingIndicator: () -> UIView = {
return LoadingIndicator()
}
/// Number of images to preload.
///
/// 0 - Preload all images (default).
public static var preload = 0
public struct PageIndicator {
public var enabled = true
public var textAttributes = [
NSFontAttributeName: UIFont.systemFontOfSize(18),
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSParagraphStyleAttributeName: {
public static var enabled = true
public static var separatorColor = UIColor(hex: "3D4757")
public static var textAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 12),
.foregroundColor: UIColor(hex: "899AB8"),
.paragraphStyle: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
}()
]
}
public struct CloseButton {
public var enabled = true
public var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFontOfSize(12),
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSParagraphStyleAttributeName: {
public static var enabled = true
public static var size: CGSize?
public static var text = NSLocalizedString("Close", comment: "")
public static var image: UIImage?
public static var textAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 16),
.foregroundColor: UIColor.white,
.paragraphStyle: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
}()
]
public var size = CGSize(width: 60, height: 25)
public var text = NSLocalizedString("Close", comment: "")
public var image: UIImage?
}
public struct DeleteButton {
public var enabled = true
public var alpha: CGFloat = 0
public var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFontOfSize(12),
NSForegroundColorAttributeName: UIColor(red:0.99, green:0.26, blue:0.18, alpha:1),
NSParagraphStyleAttributeName: {
public static var enabled = false
public static var size: CGSize?
public static var text = NSLocalizedString("Delete", comment: "")
public static var image: UIImage?
public static var textAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 16),
.foregroundColor: UIColor(hex: "FA2F5B"),
.paragraphStyle: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
}()
]
}
public struct InfoLabel {
public static var enabled = true
public static var textColor = UIColor.white
public static var ellipsisText = NSLocalizedString("Show more", comment: "")
public static var ellipsisColor = UIColor(hex: "899AB9")
public static var textAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 12),
.foregroundColor: UIColor(hex: "DBDBDB")
]
public var size = CGSize(width: 70, height: 25)
public var text = NSLocalizedString("Delete", comment: "")
public var image: UIImage?
}
public struct Zoom {
public var minimumScale: CGFloat = 1.0
public var maximumScale: CGFloat = 3.0
public static var minimumScale: CGFloat = 1.0
public static var maximumScale: CGFloat = 3.0
}
}
+373 -502
View File
@@ -2,598 +2,469 @@ import UIKit
public protocol LightboxControllerPageDelegate: class {
func lightboxControllerDidMoveToPage(controller: LightboxController, page: Int)
func lightboxController(_ controller: LightboxController, didMoveToPage page: Int)
}
public protocol LightboxControllerDismissalDelegate: class {
func lightboxControllerDidDismiss(controller: LightboxController)
func lightboxControllerWillDismiss(_ controller: LightboxController)
}
public class LightboxController: UIViewController {
public protocol LightboxControllerTouchDelegate: class {
public weak var pageDelegate: LightboxControllerPageDelegate?
public weak var dismissalDelegate: LightboxControllerDismissalDelegate?
func lightboxController(_ controller: LightboxController, didTouch image: LightboxImage, at index: Int)
}
lazy var transitionManager: LightboxTransition = { [unowned self] in
let manager = LightboxTransition()
manager.sourceViewController = self
open class LightboxController: UIViewController {
return manager
}()
// MARK: - Internal views
public var images = []
public var collectionSize = CGSizeZero
var pageLabelBottom: NSLayoutConstraint?
var pageLabelAlternative: NSLayoutConstraint?
var collectionViewHeight: NSLayoutConstraint?
var collectionViewWidth: NSLayoutConstraint?
var closeButtonTop: NSLayoutConstraint?
var closeButtonRight: NSLayoutConstraint?
var physics = false
lazy var scrollView: UIScrollView = { [unowned self] in
let scrollView = UIScrollView()
scrollView.isPagingEnabled = false
scrollView.delegate = self
scrollView.showsHorizontalScrollIndicator = false
scrollView.decelerationRate = UIScrollView.DecelerationRate.fast
lazy var config: Config = {
return LightboxConfig.sharedInstance.config
}()
return scrollView
}()
var pageLabelBottomConstant: CGFloat {
return collectionSize.width < collectionSize.height ? -20 : -2
}
lazy var overlayTapGestureRecognizer: UITapGestureRecognizer = { [unowned self] in
let gesture = UITapGestureRecognizer()
gesture.addTarget(self, action: #selector(overlayViewDidTap(_:)))
var currentOrientation: UIDeviceOrientation?
var beforeFaceOrientation: UIDeviceOrientation?
return gesture
}()
var rotating = false
lazy var effectView: UIVisualEffectView = {
let effect = UIBlurEffect(style: .dark)
let view = UIVisualEffectView(effect: effect)
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
public private(set) var page = 0 {
return view
}()
lazy var backgroundView: UIImageView = {
let view = UIImageView()
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return view
}()
// MARK: - Public views
open fileprivate(set) lazy var headerView: HeaderView = { [unowned self] in
let view = HeaderView()
view.delegate = self
return view
}()
open fileprivate(set) lazy var footerView: FooterView = { [unowned self] in
let view = FooterView()
view.delegate = self
return view
}()
open fileprivate(set) lazy var overlayView: UIView = { [unowned self] in
let view = UIView(frame: CGRect.zero)
let gradient = CAGradientLayer()
let colors = [UIColor(hex: "090909").withAlphaComponent(0), UIColor(hex: "040404")]
view.addGradientLayer(colors)
view.alpha = 0
return view
}()
// MARK: - Properties
open fileprivate(set) var currentPage = 0 {
didSet {
page = min(images.count - 1, max(0, page))
currentPage = min(numberOfPages - 1, max(0, currentPage))
footerView.updatePage(currentPage + 1, numberOfPages)
footerView.updateText(pageViews[currentPage].image.text)
let text = "\(page + 1)/\(images.count)"
pageLabel.attributedText = NSAttributedString(string: text,
attributes: config.pageIndicator.textAttributes)
pageLabel.sizeToFit()
if page == images.count - 1 {
if currentPage == numberOfPages - 1 {
seen = true
}
pageDelegate?.lightboxControllerDidMoveToPage(self, page: page)
reconfigurePagesForPreload()
pageDelegate?.lightboxController(self, didMoveToPage: currentPage)
if let image = pageViews[currentPage].imageView.image, dynamicBackground {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.125) {
self.loadDynamicBackground(image)
}
}
}
}
public private(set) var seen = false
lazy var collectionView: UICollectionView = { [unowned self] in
let collectionView = UICollectionView(frame: CGRectZero,
collectionViewLayout: self.collectionViewLayout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .blackColor()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.decelerationRate = UIScrollViewDecelerationRateFast
collectionView.registerClass(LightboxViewCell.self,
forCellWithReuseIdentifier: LightboxViewCell.reuseIdentifier)
return collectionView
}()
lazy var collectionViewLayout: UICollectionViewLayout = { [unowned self] in
let layout = CenterCellCollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
layout.minimumInteritemSpacing = self.config.spacing
layout.minimumLineSpacing = self.config.spacing
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
return layout
}()
lazy var pageLabel: UILabel = { [unowned self] in
let label = UILabel(frame: CGRectZero)
label.translatesAutoresizingMaskIntoConstraints = false
label.hidden = !self.config.pageIndicator.enabled
return label
}()
lazy var closeButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: self.config.closeButton.text,
attributes: self.config.closeButton.textAttributes)
let button = UIButton(type: .System)
button.tintColor = self.config.closeButton.textAttributes[NSForegroundColorAttributeName] as? UIColor
button.translatesAutoresizingMaskIntoConstraints = false
button.setAttributedTitle(title, forState: .Normal)
button.addTarget(self, action: "closeButtonDidTouchUpInside:",
forControlEvents: .TouchUpInside)
if let image = self.config.closeButton.image {
button.setBackgroundImage(image, forState: .Normal)
}
return button
}()
lazy var deleteButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: self.config.deleteButton.text,
attributes: self.config.deleteButton.textAttributes)
let button = UIButton(type: .System)
button.tintColor = self.config.deleteButton.textAttributes[NSForegroundColorAttributeName] as? UIColor
button.translatesAutoresizingMaskIntoConstraints = false
button.setAttributedTitle(title, forState: .Normal)
button.alpha = self.config.deleteButton.alpha
button.addTarget(self, action: "deleteButtonDidPress:",
forControlEvents: .TouchUpInside)
if let image = self.config.deleteButton.image {
button.setBackgroundImage(image, forState: .Normal)
}
return button
}()
// MARK: Initializers
public required init(images: [String], config: Config? = nil,
pageDelegate: LightboxControllerPageDelegate? = nil,
dismissalDelegate: LightboxControllerDismissalDelegate? = nil) {
self.images = images
self.pageDelegate = pageDelegate
self.dismissalDelegate = dismissalDelegate
if let config = config {
LightboxConfig.sharedInstance.config = config
}
super.init(nibName: nil, bundle: nil)
open var numberOfPages: Int {
return pageViews.count
}
public required init(imagesUI: [UIImage], config: Config? = nil,
pageDelegate: LightboxControllerPageDelegate? = nil,
dismissalDelegate: LightboxControllerDismissalDelegate? = nil) {
self.images = imagesUI
self.pageDelegate = pageDelegate
self.dismissalDelegate = dismissalDelegate
if let config = config {
LightboxConfig.sharedInstance.config = config
open var dynamicBackground: Bool = false {
didSet {
if dynamicBackground == true {
effectView.frame = view.frame
backgroundView.frame = effectView.frame
view.insertSubview(effectView, at: 0)
view.insertSubview(backgroundView, at: 0)
} else {
effectView.removeFromSuperview()
backgroundView.removeFromSuperview()
}
}
}
super.init(nibName: nil, bundle: nil)
open var spacing: CGFloat = 20 {
didSet {
configureLayout(view.bounds.size)
}
}
open var images: [LightboxImage] {
get {
return pageViews.map { $0.image }
}
set(value) {
initialImages = value
configurePages(value)
}
}
open weak var pageDelegate: LightboxControllerPageDelegate?
open weak var dismissalDelegate: LightboxControllerDismissalDelegate?
open weak var imageTouchDelegate: LightboxControllerTouchDelegate?
open internal(set) var presented = false
open fileprivate(set) var seen = false
lazy var transitionManager: LightboxTransition = LightboxTransition()
var pageViews = [PageView]()
var statusBarHidden = false
fileprivate var initialImages: [LightboxImage]
fileprivate let initialPage: Int
// MARK: - Initializers
public init(images: [LightboxImage] = [], startIndex index: Int = 0) {
self.initialImages = images
self.initialPage = index
super.init(nibName: nil, bundle: nil)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View Lifecycle
// MARK: - View lifecycle
public override func viewDidLoad() {
open override func viewDidLoad() {
super.viewDidLoad()
collectionSize = CGSizeMake(view.frame.width, view.frame.height)
for subview in [collectionView, pageLabel, closeButton, deleteButton] {
self.view.addSubview(subview)
}
// 9 July 2020: @3lvis
// Lightbox hasn't been optimized to be used in presentation styles other than fullscreen.
modalPresentationStyle = .fullScreen
statusBarHidden = UIApplication.shared.isStatusBarHidden
view.backgroundColor = UIColor.black
transitionManager.lightboxController = self
transitionManager.scrollView = scrollView
transitioningDelegate = transitionManager
transitionManager.delegate = self
view.backgroundColor = UIColor.blackColor()
let orientationsSupported: [String] = NSBundle.mainBundle().objectForInfoDictionaryKey("UISupportedInterfaceOrientations") as! [String]
[scrollView, overlayView, headerView, footerView].forEach { view.addSubview($0) }
overlayView.addGestureRecognizer(overlayTapGestureRecognizer)
currentOrientation = UIDevice.currentDevice().orientation
beforeFaceOrientation = UIDevice.currentDevice().orientation
configurePages(initialImages)
if orientationsSupported.first == "UIInterfaceOrientationPortrait"
&& orientationsSupported.count == 1 {
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "deviceDidRotate",
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
setupConstraints()
page = 0
goTo(initialPage, animated: false)
}
public override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !presented {
presented = true
configureLayout(view.bounds.size)
}
}
if config.hideStatusBar {
UIApplication.sharedApplication().setStatusBarHidden(true,
withAnimation: .Fade)
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
footerView.frame.size = CGSize(
width: view.bounds.width,
height: 100
)
footerView.frame.origin = CGPoint(
x: 0,
y: view.bounds.height - footerView.frame.height
)
headerView.frame = CGRect(
x: 0,
y: 16,
width: view.bounds.width,
height: 100
)
}
open override var prefersStatusBarHidden: Bool {
return LightboxConfig.hideStatusBar
}
// MARK: - Rotation
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { _ in
self.configureLayout(size)
}, completion: nil)
}
// MARK: - Configuration
func configurePages(_ images: [LightboxImage]) {
pageViews.forEach { $0.removeFromSuperview() }
pageViews = []
let preloadIndicies = calculatePreloadIndicies()
for i in 0..<images.count {
let pageView = PageView(image: preloadIndicies.contains(i) ? images[i] : LightboxImageStub())
pageView.pageViewDelegate = self
scrollView.addSubview(pageView)
pageViews.append(pageView)
}
let orientationsSupported: [String] = NSBundle.mainBundle().objectForInfoDictionaryKey("UISupportedInterfaceOrientations") as! [String]
configureLayout(view.bounds.size)
}
if orientationsSupported.first == "UIInterfaceOrientationPortrait"
&& orientationsSupported.count == 1 {
if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft
|| UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {
deviceDidRotate()
func reconfigurePagesForPreload() {
let preloadIndicies = calculatePreloadIndicies()
for i in 0..<initialImages.count {
let pageView = pageViews[i]
if preloadIndicies.contains(i) {
if type(of: pageView.image) == LightboxImageStub.self {
pageView.update(with: initialImages[i])
}
} else {
if type(of: pageView.image) != LightboxImageStub.self {
pageView.update(with: LightboxImageStub())
}
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
// MARK: - Handle rotation
func deviceDidRotate() {
let orientation = UIDevice.currentDevice().orientation
let orientations: [UIDeviceOrientation] = [.FaceUp, .FaceDown]
let currentIsFace = orientations.filter({ $0 == self.currentOrientation }).first != nil
let nextIsFace = orientations.filter({ $0 == orientation }).first != nil
if nextIsFace {
beforeFaceOrientation = currentOrientation
}
currentOrientation = orientation
if (!currentIsFace && nextIsFace) ||
(currentIsFace && !nextIsFace && orientation == beforeFaceOrientation) {
return
}
rotating = true
var transform = CGAffineTransformIdentity
if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft {
transform = moveCollectionView(true)
moveViews(true)
transitionManager.panGestureRecognizer.enabled = false
} else if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {
transform = moveCollectionView(false)
moveViews(false)
transitionManager.panGestureRecognizer.enabled = false
} else if UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait {
for constraint in [collectionViewHeight!, collectionViewWidth!,
closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.removeConstraint(constraint)
}
standardCollectionViewConstraints()
standardCloseButtonConstraints()
standardPageLabelConstraints()
collectionView.alpha = 0
transitionManager.panGestureRecognizer.enabled = true
}
if UIDevice.currentDevice().orientation != UIDeviceOrientation.PortraitUpsideDown {
UIView.animateWithDuration(0.1, animations: { [unowned self] in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.alpha = 0 }
}, completion: { finished in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.transform = transform }
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: UICollectionViewScrollPosition(), animated: false)
UIView.animateWithDuration(0.3, animations: { [unowned self] in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.alpha = 1 }
self.rotating = false
})
})
}
if UIDevice.currentDevice().orientation != UIDeviceOrientation.PortraitUpsideDown {
UIView.animateWithDuration(0.3, animations: { [unowned self] in
self.collectionView.transform = transform
self.closeButton.transform = transform
self.pageLabel.transform = transform
}, completion: { _ in
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: UICollectionViewScrollPosition(), animated: true)
self.rotating = false
})
}
if UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown {
rotating = false
}
}
// MARK: - Autolayout
func setupConstraints() {
let attributes: [NSLayoutAttribute] = [.CenterX, .CenterY]
for attribute in attributes {
view.addConstraint(NSLayoutConstraint(item: collectionView, attribute: attribute,
relatedBy: .Equal, toItem: self.view, attribute: attribute, multiplier: 1, constant: 0))
}
standardCollectionViewConstraints()
standardPageLabelConstraints()
standardCloseButtonConstraints()
standardDeleteButtonConstraints()
view.addConstraint(NSLayoutConstraint(item: closeButton, attribute: .Width,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.closeButton.size.width))
view.addConstraint(NSLayoutConstraint(item: closeButton, attribute: .Height,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.closeButton.size.height))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Width,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.deleteButton.size.width))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Height,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.deleteButton.size.height))
}
// MARK: - Orientation
public override func shouldAutorotate() -> Bool {
return true
}
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.All
}
public override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
rotating = true
collectionSize = size
collectionView.collectionViewLayout.invalidateLayout()
coordinator.animateAlongsideTransition({ _ in
self.collectionView.collectionViewLayout.invalidateLayout()
self.pageLabelBottom?.constant = self.pageLabelBottomConstant
}, completion: { _ in
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.view.layoutIfNeeded()
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: .CenteredHorizontally,
animated: false)
self.rotating = false
})
}
// MARK: - Pagination
public func goTo(page: Int, animated: Bool = true) {
if page >= 0 && page < images.count {
var offset = collectionView.contentOffset
offset.x = CGFloat(page) * collectionSize.width
collectionView.setContentOffset(offset,
animated: animated)
open func goTo(_ page: Int, animated: Bool = true) {
guard page >= 0 && page < numberOfPages else {
return
}
currentPage = page
var offset = scrollView.contentOffset
offset.x = CGFloat(page) * (scrollView.frame.width + spacing)
let shouldAnimated = view.window != nil ? animated : false
scrollView.setContentOffset(offset, animated: shouldAnimated)
}
public func next(animated: Bool = true) {
goTo(page + 1, animated: animated)
open func next(_ animated: Bool = true) {
goTo(currentPage + 1, animated: animated)
}
public func previous(animated: Bool = true) {
goTo(page - 1, animated: animated)
open func previous(_ animated: Bool = true) {
goTo(currentPage - 1, animated: animated)
}
// MARK: - Actions
func closeButtonDidTouchUpInside(sender: UIButton) {
dismissalDelegate?.lightboxControllerDidDismiss(self)
@objc func overlayViewDidTap(_ tapGestureRecognizer: UITapGestureRecognizer) {
footerView.expand(false)
}
func deleteButtonDidPress(button: UIButton) {
button.enabled = false
var indexPath = NSIndexPath()
let index = page
let array = images.mutableCopy() as! NSMutableArray
// MARK: - Layout
if page < images.count - 1 {
indexPath = NSIndexPath(forRow: page + 1, inSection: 0)
} else if page == images.count - 1 && images.count != 1 {
indexPath = NSIndexPath(forRow: page - 1, inSection: 0)
open func configureLayout(_ size: CGSize) {
scrollView.frame.size = size
scrollView.contentSize = CGSize(
width: size.width * CGFloat(numberOfPages) + spacing * CGFloat(numberOfPages - 1),
height: size.height)
scrollView.contentOffset = CGPoint(x: CGFloat(currentPage) * (size.width + spacing), y: 0)
for (index, pageView) in pageViews.enumerated() {
var frame = scrollView.bounds
frame.origin.x = (frame.width + spacing) * CGFloat(index)
pageView.frame = frame
pageView.configureLayout()
if index != numberOfPages - 1 {
pageView.frame.size.width += spacing
}
}
[headerView, footerView].forEach { ($0 as AnyObject).configureLayout() }
overlayView.frame = scrollView.frame
overlayView.resizeGradientLayer()
}
fileprivate func loadDynamicBackground(_ image: UIImage) {
backgroundView.image = image
backgroundView.layer.add(CATransition(), forKey: "fade")
}
func toggleControls(pageView: PageView?, visible: Bool, duration: TimeInterval = 0.1, delay: TimeInterval = 0) {
let alpha: CGFloat = visible ? 1.0 : 0.0
pageView?.playButton.isHidden = !visible
UIView.animate(withDuration: duration, delay: delay, options: [], animations: {
self.headerView.alpha = alpha
self.footerView.alpha = alpha
pageView?.playButton.alpha = alpha
}, completion: nil)
}
// MARK: - Helper functions
func calculatePreloadIndicies () -> [Int] {
var preloadIndicies: [Int] = []
let preload = LightboxConfig.preload
if preload > 0 {
let lb = max(0, currentPage - preload)
let rb = min(initialImages.count, currentPage + preload)
for i in lb..<rb {
preloadIndicies.append(i)
}
} else {
if array.count != 0 {
array.removeObjectAtIndex(index)
}
images = array
dismissalDelegate?.lightboxControllerDidDismiss(self)
}
if images.count != 0 {
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: true)
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.25 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) { [unowned self] in
array.removeObjectAtIndex(index)
self.collectionView.scrollToItemAtIndexPath(NSIndexPath(forRow: index, inSection: 0), atScrollPosition: .Left, animated: false)
self.images = array
self.page = index
self.collectionView.reloadData()
button.enabled = true
}
preloadIndicies = [Int](0..<initialImages.count)
}
return preloadIndicies
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension LightboxController: UICollectionViewDelegateFlowLayout {
public func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return collectionSize
}
}
// MARK: - UICollectionViewDelegate
extension LightboxController: UICollectionViewDelegate { }
// MARK: - UIScrollViewDelegate
extension LightboxController: UIScrollViewDelegate {
public func scrollViewDidScroll(scrollView: UIScrollView) {
if !rotating {
let pageWidth = collectionSize.width
let currentPage = Int(floor((collectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
if currentPage != page { page = currentPage }
}
}
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
var speed: CGFloat = velocity.x < 0 ? -2 : 2
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if let cell = collectionView.visibleCells().first as? LightboxViewCell {
cell.parentViewController = self
cell.setupTransitionManager()
if velocity.x == 0 {
speed = 0
}
let pageWidth = scrollView.bounds.width + spacing
var x = scrollView.contentOffset.x + speed * 60.0
if speed > 0 {
x = ceil(x / pageWidth) * pageWidth
} else if speed < -0 {
x = floor(x / pageWidth) * pageWidth
} else {
x = round(x / pageWidth) * pageWidth
}
targetContentOffset.pointee.x = x
currentPage = Int(x / pageWidth)
}
}
extension LightboxController: LightboxTransitionDelegate {
// MARK: - PageViewDelegate
func transitionDidDismissController(controller: LightboxController) {
dismissalDelegate?.lightboxControllerDidDismiss(controller)
extension LightboxController: PageViewDelegate {
func remoteImageDidLoad(_ image: UIImage?, imageView: UIImageView) {
guard let image = image, dynamicBackground else {
return
}
let imageViewFrame = imageView.convert(imageView.frame, to: view)
guard view.frame.intersects(imageViewFrame) else {
return
}
loadDynamicBackground(image)
}
func pageViewDidZoom(_ pageView: PageView) {
let duration = pageView.hasZoomed ? 0.1 : 0.5
toggleControls(pageView: pageView, visible: !pageView.hasZoomed, duration: duration, delay: 0.5)
}
func pageView(_ pageView: PageView, didTouchPlayButton videoURL: URL) {
LightboxConfig.handleVideo(self, videoURL)
}
func pageViewDidTouch(_ pageView: PageView) {
guard !pageView.hasZoomed else { return }
imageTouchDelegate?.lightboxController(self, didTouch: images[currentPage], at: currentPage)
let visible = (headerView.alpha == 1.0)
toggleControls(pageView: pageView, visible: !visible)
}
}
// MARK: Custom autolayout
// MARK: - HeaderViewDelegate
extension LightboxController {
extension LightboxController: HeaderViewDelegate {
private func moveCollectionView(left: Bool) -> CGAffineTransform {
let value: CGFloat = left ? 1.57 : -1.57
let transform = CGAffineTransformMakeRotation(value)
let size = CGSizeMake(view.frame.height, view.frame.width)
func headerView(_ headerView: HeaderView, didPressDeleteButton deleteButton: UIButton) {
deleteButton.isEnabled = false
view.removeConstraint(collectionViewHeight!)
view.removeConstraint(collectionViewWidth!)
collectionViewHeight = NSLayoutConstraint(item: collectionView, attribute: .Height,
relatedBy: .Equal, toItem: view, attribute: .Width,
multiplier: 1, constant: 0)
collectionViewWidth = NSLayoutConstraint(item: collectionView, attribute: .Width,
relatedBy: .Equal, toItem: view, attribute: .Height,
multiplier: 1, constant: 0)
view.addConstraint(collectionViewHeight!)
view.addConstraint(collectionViewWidth!)
collectionSize = size
collectionView.alpha = 0
collectionView.collectionViewLayout.invalidateLayout()
view.layoutIfNeeded()
return transform
}
private func standardPageLabelConstraints() {
pageLabelAlternative = NSLayoutConstraint(item: pageLabel, attribute: .CenterX,
relatedBy: .Equal, toItem: view, attribute: .CenterX,
multiplier: 1, constant: 0)
pageLabelBottom = NSLayoutConstraint(item: pageLabel, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: pageLabelBottomConstant)
view.addConstraint(pageLabelAlternative!)
view.addConstraint(pageLabelBottom!)
}
private func standardCollectionViewConstraints() {
collectionViewWidth = NSLayoutConstraint(item: collectionView, attribute: .Width,
relatedBy: .Equal, toItem: view, attribute: .Width,
multiplier: 1, constant: 0)
collectionViewHeight = NSLayoutConstraint(item: collectionView, attribute: .Height,
relatedBy: .Equal, toItem: view, attribute: .Height,
multiplier: 1, constant: 0)
collectionSize = CGSizeMake(view.frame.width, view.frame.height)
collectionView.reloadData()
view.addConstraint(collectionViewWidth!)
view.addConstraint(collectionViewHeight!)
}
private func standardCloseButtonConstraints() {
closeButtonTop = NSLayoutConstraint(item: closeButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 16)
closeButtonRight = NSLayoutConstraint(item: closeButton, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: -17)
view.addConstraint(closeButtonTop!)
view.addConstraint(closeButtonRight!)
}
private func standardDeleteButtonConstraints() {
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 16))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 17))
}
private func moveViews(left: Bool) {
for constraint in [closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.removeConstraint(constraint)
guard numberOfPages != 1 else {
pageViews.removeAll()
self.headerView(headerView, didPressCloseButton: headerView.closeButton)
return
}
closeButtonRight = left ?
NSLayoutConstraint(item: closeButton, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: 0) :
NSLayoutConstraint(item: closeButton, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 0)
let prevIndex = currentPage
closeButtonTop = left
? NSLayoutConstraint(item: closeButton, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: -35)
: NSLayoutConstraint(item: closeButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 35)
pageLabelBottom = left
? NSLayoutConstraint(item: pageLabel, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 20)
: NSLayoutConstraint(item: pageLabel, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 20)
pageLabelAlternative = left
? NSLayoutConstraint(item: pageLabel, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: -20)
: NSLayoutConstraint(item: pageLabel, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: -20)
for constraint in [closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.addConstraint(constraint)
if currentPage == numberOfPages - 1 {
previous()
} else {
next()
currentPage -= 1
}
self.pageViews.remove(at: prevIndex).removeFromSuperview()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
self.configureLayout(self.view.bounds.size)
self.currentPage = Int(self.scrollView.contentOffset.x / self.view.bounds.width)
deleteButton.isEnabled = true
}
}
func headerView(_ headerView: HeaderView, didPressCloseButton closeButton: UIButton) {
closeButton.isEnabled = false
presented = false
dismissalDelegate?.lightboxControllerWillDismiss(self)
dismiss(animated: true, completion: nil)
}
}
// MARK: - FooterViewDelegate
extension LightboxController: FooterViewDelegate {
public func footerView(_ footerView: FooterView, didExpand expanded: Bool) {
UIView.animate(withDuration: 0.25, animations: {
self.overlayView.alpha = expanded ? 1.0 : 0.0
self.headerView.deleteButton.alpha = expanded ? 0.0 : 1.0
})
}
}
-41
View File
@@ -1,41 +0,0 @@
import UIKit
extension LightboxController: UICollectionViewDataSource {
public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cellIdentifier = LightboxViewCell.reuseIdentifier
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier,
forIndexPath: indexPath) as! LightboxViewCell
let image: AnyObject = images[indexPath.row]
let config = LightboxConfig.sharedInstance.config
cell.parentViewController = self
cell.loadingIndicator.alpha = 0
cell.setupTransitionManager()
if let imageString = image as? String {
if let imageURL = NSURL(string: imageString) where config.remoteImages {
cell.loadingIndicator.alpha = 1
config.loadImage(
imageView: cell.lightboxView.imageView, URL: imageURL) { error in
if error == nil {
cell.loadingIndicator.alpha = 0
cell.lightboxView.updateViewLayout()
}
}
} else {
cell.lightboxView.imageView.image = UIImage(named: imageString)
cell.lightboxView.updateViewLayout()
}
} else if let image = image as? UIImage {
cell.lightboxView.imageView.image = image
cell.lightboxView.updateViewLayout()
}
return cell
}
}
+51
View File
@@ -0,0 +1,51 @@
import UIKit
import Imaginary
open class LightboxImage {
open fileprivate(set) var image: UIImage?
open fileprivate(set) var imageURL: URL?
open fileprivate(set) var videoURL: URL?
open fileprivate(set) var imageClosure: (() -> UIImage)?
open var text: String
// MARK: - Initialization
internal init(text: String = "") {
self.text = text
}
public init(image: UIImage, text: String = "", videoURL: URL? = nil) {
self.image = image
self.text = text
self.videoURL = videoURL
}
public init(imageURL: URL, text: String = "", videoURL: URL? = nil) {
self.imageURL = imageURL
self.text = text
self.videoURL = videoURL
}
public init(imageClosure: @escaping () -> UIImage, text: String = "", videoURL: URL? = nil) {
self.imageClosure = imageClosure
self.text = text
self.videoURL = videoURL
}
open func addImageTo(_ imageView: UIImageView, completion: ((UIImage?) -> Void)? = nil) {
if let image = image {
imageView.image = image
completion?(image)
} else if let imageURL = imageURL {
LightboxConfig.loadImage(imageView, imageURL, completion)
} else if let imageClosure = imageClosure {
let img = imageClosure()
imageView.image = img
completion?(img)
} else {
imageView.image = nil
completion?(nil)
}
}
}
+10
View File
@@ -0,0 +1,10 @@
import UIKit
internal class LightboxImageStub: LightboxImage {
// MARK: - Initialization
init () {
super.init()
}
}
-254
View File
@@ -1,254 +0,0 @@
import UIKit
protocol LightboxTransitionDelegate: class {
func transitionDidDismissController(controller: LightboxController)
}
class LightboxTransition: UIPercentDrivenInteractiveTransition {
struct Timing {
static let transition: NSTimeInterval = 0.4
}
lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
let panGestureRecognizer = UIPanGestureRecognizer()
panGestureRecognizer.addTarget(self, action: "handlePanGesture:")
panGestureRecognizer.delegate = self
return panGestureRecognizer
}()
var presentingViewController = false
var interactive = false
var animator: UIDynamicAnimator!
var attachmentBehavior: UIAttachmentBehavior!
var gravityBehaviour: UIGravityBehavior!
var snapBehavior: UISnapBehavior!
weak var sourceViewController: LightboxController!
weak var delegate: LightboxTransitionDelegate?
weak var lightboxController: LightboxController!
weak var sourceViewCell: LightboxViewCell? {
didSet {
sourceViewCell?.addGestureRecognizer(panGestureRecognizer)
}
}
func transition(controller: LightboxController, show: Bool) {
lightboxController = controller
if UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeLeft
&& UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeRight {
if sourceViewCell != nil {
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, UIScreen.mainScreen().bounds.height/2)
}
controller.pageLabel.transform = show ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(0, 250)
for button in [controller.closeButton, controller.deleteButton] {
button.transform = show
? CGAffineTransformIdentity
: CGAffineTransformMakeTranslation(0, -250)
}
}
if presentingViewController {
controller.collectionView.transform = show ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.5, 0.5)
controller.view.alpha = show ? 1 : 0.01
} else if !interactive {
controller.view.alpha = show ? 1 : 0.1
} else {
controller.view.alpha = show ? 1 : 0.95
}
}
}
// MARK: Transitioning delegate
extension LightboxTransition : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return Timing.transition
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let screens : (from: UIViewController, to: UIViewController) = (
transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!,
transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!)
let lightboxViewController = !presentingViewController
? screens.from as! LightboxController
: screens.to as! LightboxController
let viewController = !presentingViewController
? screens.to as UIViewController
: screens.from as UIViewController
for controller in [viewController, lightboxViewController] {
containerView?.addSubview(controller.view)
}
if presentingViewController {
transition(lightboxViewController, show: false)
}
UIView.animateWithDuration(Timing.transition, animations: { [unowned self] in
self.transition(lightboxViewController, show: self.presentingViewController)
}, completion: { _ in
if transitionContext.transitionWasCancelled() {
UIView.animateWithDuration(Timing.transition/3, animations: { [unowned self] in
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, UIScreen.mainScreen().bounds.height/2)
self.transition(lightboxViewController, show: true)
}, completion: { finished in
transitionContext.completeTransition(false)
UIApplication.sharedApplication().keyWindow?.addSubview(screens.from.view)
})
} else {
if self.lightboxController.view.alpha < 0.97 && !self.presentingViewController {
UIView.animateWithDuration(0.4, animations: {
lightboxViewController.view.alpha = 0
}, completion: { _ in
transitionContext.completeTransition(true)
})
} else {
transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow?.addSubview(screens.to.view)
}
}
})
}
}
// MARK: Transition delegate
extension LightboxTransition : UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController,
presentingController presenting: UIViewController,
sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presentingViewController = true
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presentingViewController = false
return self
}
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
}
// MARK: Interactive transition delegate
extension LightboxTransition {
func handlePanGesture(panGestureRecognizer: UIPanGestureRecognizer) {
guard let imageView = sourceViewCell?.lightboxView.imageView else { return }
let location = panGestureRecognizer.locationInView(sourceViewCell?.lightboxView)
let boxLocation = panGestureRecognizer.locationInView(imageView)
let translation = panGestureRecognizer.translationInView(sourceViewCell?.lightboxView)
let percentage = fabs(translation.y / UIScreen.mainScreen().bounds.height)
if percentage > 0.35 {
transition(lightboxController, show: false)
}
if let controller = sourceViewCell?.parentViewController where controller.physics {
if panGestureRecognizer.state == UIGestureRecognizerState.Began {
interactive = true
sourceViewController.dismissViewControllerAnimated(true, completion: nil)
animator.removeBehavior(snapBehavior)
let centerOffset = UIOffsetMake(boxLocation.x - CGRectGetMidX(imageView.bounds),
boxLocation.y - CGRectGetMidY(imageView.bounds))
attachmentBehavior = UIAttachmentBehavior(item: imageView,
offsetFromCenter: centerOffset, attachedToAnchor: location)
attachmentBehavior.frequency = 0
animator.addBehavior(attachmentBehavior)
} else if panGestureRecognizer.state == UIGestureRecognizerState.Changed {
attachmentBehavior.anchorPoint = location
updateInteractiveTransition(percentage)
} else if panGestureRecognizer.state == UIGestureRecognizerState.Ended {
interactive = false
if percentage > 0.35 {
finishInteractiveTransition()
delegate?.transitionDidDismissController(lightboxController)
} else {
cancelInteractiveTransition()
if let cell = sourceViewCell {
animator.removeBehavior(attachmentBehavior)
snapBehavior = UISnapBehavior(item: imageView,
snapToPoint: cell.lightboxView.center)
animator.addBehavior(snapBehavior)
}
}
}
} else {
if panGestureRecognizer.state == .Began {
interactive = true
sourceViewController.dismissViewControllerAnimated(true, completion: nil)
} else if panGestureRecognizer.state == .Changed {
imageView.center = CGPointMake(imageView.center.x, UIScreen.mainScreen().bounds.height/2 + translation.y)
updateInteractiveTransition(percentage)
} else {
interactive = false
if percentage > 0.35 {
finishInteractiveTransition()
delegate?.transitionDidDismissController(lightboxController)
lightboxController.collectionView.alpha = 0
} else {
cancelInteractiveTransition()
}
}
}
}
override func finishInteractiveTransition() {
super.finishInteractiveTransition()
guard let cell = sourceViewCell else { return }
let point = (cell.lightboxView.imageView.center.y - UIScreen.mainScreen().bounds.height/2) * 10
UIView.animateWithDuration(Timing.transition, animations: { [unowned self] in
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, point)
}, completion: { _ in
guard let cell = self.sourceViewCell else { return }
if let controller = cell.parentViewController where controller.physics {
self.animator.removeBehavior(self.attachmentBehavior)
self.snapBehavior = UISnapBehavior(item: cell.lightboxView.imageView,
snapToPoint: cell.lightboxView.center)
self.animator.addBehavior(self.snapBehavior)
}
})
sourceViewController.collectionView.scrollRectToVisible(
CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height),
animated: false)
}
}
// MARK: Gesture recognizer delegate methods
extension LightboxTransition : UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translationInView(sourceViewCell?.superview!)
if fabs(translation.x) < fabs(translation.y) {
return true
}
}
return false
}
}
-165
View File
@@ -1,165 +0,0 @@
import UIKit
public class LightboxView: UIView {
public var minimumZoomScale: CGFloat = 1
public var maximumZoomScale: CGFloat = 3
var lastZoomScale: CGFloat = -1
lazy var imageView: UIImageView = {
let imageView = UIImageView(frame: CGRectZero)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.userInteractionEnabled = true
return imageView
}()
lazy var scrollView: UIScrollView = { [unowned self] in
let scrollView = UIScrollView(frame: CGRectZero)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.multipleTouchEnabled = true
scrollView.minimumZoomScale = self.minimumZoomScale
scrollView.maximumZoomScale = self.maximumZoomScale
scrollView.delegate = self
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
return scrollView
}()
var imageConstraintLeading: NSLayoutConstraint!
var imageConstraintTrailing: NSLayoutConstraint!
var imageConstraintTop: NSLayoutConstraint!
var imageConstraintBottom: NSLayoutConstraint!
var constraintsAdded = false
// MARK: - Initialization
public init(frame: CGRect, image: UIImage? = nil) {
super.init(frame: frame)
imageView.image = image
let config = LightboxConfig.sharedInstance.config
backgroundColor = config.backgroundColor
minimumZoomScale = config.zoom.minimumScale
maximumZoomScale = config.zoom.maximumScale
scrollView.addSubview(imageView)
addSubview(scrollView)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View lifecycle
public override func didMoveToSuperview() {
setUpConstraints()
}
// MARK: - Public methods
public func updateViewLayout() {
if constraintsAdded {
updateImageConstraints()
updateZoom()
}
}
// MARK: - Autolayout
public func setUpConstraints() {
if !constraintsAdded {
let layoutAttributes: [NSLayoutAttribute] = [.Leading, .Trailing, .Top, .Bottom]
for layoutAttribute in layoutAttributes {
addConstraint(NSLayoutConstraint(item: self.scrollView, attribute: layoutAttribute,
relatedBy: .Equal, toItem: self, attribute: layoutAttribute,
multiplier: 1, constant: 0))
}
imageConstraintLeading = NSLayoutConstraint(item: imageView, attribute: .Leading,
relatedBy: .Equal, toItem: scrollView, attribute: .Leading,
multiplier: 1, constant: 0)
imageConstraintTrailing = NSLayoutConstraint(item: imageView, attribute: .Trailing,
relatedBy: .Equal, toItem: scrollView, attribute: .Trailing,
multiplier: 1, constant: 0)
imageConstraintTop = NSLayoutConstraint(item: imageView, attribute: .Top,
relatedBy: .Equal, toItem: scrollView, attribute: .Top,
multiplier: 1, constant: 0)
imageConstraintBottom = NSLayoutConstraint(item: imageView, attribute: .Bottom,
relatedBy: .Equal, toItem: scrollView, attribute: .Bottom,
multiplier: 1, constant: 0)
addConstraints([imageConstraintLeading, imageConstraintTrailing,
imageConstraintTop, imageConstraintBottom])
layoutIfNeeded()
scrollView.contentSize = CGSize(width: frame.size.width, height: frame.size.height)
constraintsAdded = true
}
}
public func updateImageConstraints() {
if let image = imageView.image {
// Center image
var hPadding = (bounds.size.width - scrollView.zoomScale * image.size.width) / 2
if hPadding < 0 {
hPadding = 0
}
var vPadding = (bounds.size.height - scrollView.zoomScale * image.size.height) / 2
if vPadding < 0 {
vPadding = 0
}
for constraint in [imageConstraintLeading, imageConstraintTrailing] { constraint.constant = hPadding }
for constraint in [imageConstraintTop, imageConstraintBottom] { constraint.constant = vPadding }
layoutIfNeeded()
}
}
// MARK: - Zoom
public func updateZoom() {
if let image = imageView.image {
var minimumZoom = min(
bounds.size.width / image.size.width,
bounds.size.height / image.size.height)
if minimumZoom > 1 {
minimumZoom = 1
}
scrollView.minimumZoomScale = minimumZoom
if minimumZoom == lastZoomScale {
minimumZoom += 0.000001
}
scrollView.zoomScale = minimumZoom
lastZoomScale = minimumZoom
}
}
}
// MARK: - UIScrollViewDelegate
extension LightboxView: UIScrollViewDelegate {
public func scrollViewDidZoom(scrollView: UIScrollView) {
updateImageConstraints()
}
public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
-63
View File
@@ -1,63 +0,0 @@
import UIKit
public class LightboxViewCell: UICollectionViewCell {
public static let reuseIdentifier: String = "LightboxViewCell"
var constraintsAdded = false
weak var parentViewController: LightboxController?
public lazy var lightboxView: LightboxView = { [unowned self] in
let lightboxView = LightboxView(frame: self.bounds)
lightboxView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(lightboxView)
return lightboxView
}()
public lazy var loadingIndicator: UIActivityIndicatorView = {
let loadingIndicator = UIActivityIndicatorView(activityIndicatorStyle: .White)
loadingIndicator.startAnimating()
loadingIndicator.alpha = 0
loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
return loadingIndicator
}()
public override func layoutSubviews() {
super.layoutSubviews()
if loadingIndicator.superview == nil { self.contentView.addSubview(loadingIndicator) }
setupConstraints()
lightboxView.updateViewLayout()
}
public func setupTransitionManager() {
guard let controller = parentViewController else { return }
controller.transitionManager.sourceViewCell = self
controller.transitionManager.animator = UIDynamicAnimator(referenceView: lightboxView)
}
private func setupConstraints() {
if !constraintsAdded {
let layoutAttributes: [NSLayoutAttribute] = [.Leading, .Trailing, .Top, .Bottom]
for layoutAttribute in layoutAttributes {
addConstraint(NSLayoutConstraint(item: lightboxView, attribute: layoutAttribute,
relatedBy: .Equal, toItem: contentView, attribute: layoutAttribute,
multiplier: 1, constant: 0))
}
addConstraint(NSLayoutConstraint(item: loadingIndicator, attribute: .CenterX,
relatedBy: .Equal, toItem: self.contentView, attribute: .CenterX,
multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: loadingIndicator, attribute: .CenterY,
relatedBy: .Equal, toItem: self.contentView, attribute: .CenterY,
multiplier: 1, constant: 0))
constraintsAdded = true
}
}
}
+125
View File
@@ -0,0 +1,125 @@
import UIKit
public protocol FooterViewDelegate: class {
func footerView(_ footerView: FooterView, didExpand expanded: Bool)
}
open class FooterView: UIView {
open fileprivate(set) lazy var infoLabel: InfoLabel = { [unowned self] in
let label = InfoLabel(text: "")
label.isHidden = !LightboxConfig.InfoLabel.enabled
label.textColor = LightboxConfig.InfoLabel.textColor
label.isUserInteractionEnabled = true
label.delegate = self
return label
}()
open fileprivate(set) lazy var pageLabel: UILabel = { [unowned self] in
let label = UILabel(frame: CGRect.zero)
label.isHidden = !LightboxConfig.PageIndicator.enabled
label.numberOfLines = 1
return label
}()
open fileprivate(set) lazy var separatorView: UIView = { [unowned self] in
let view = UILabel(frame: CGRect.zero)
view.isHidden = !LightboxConfig.PageIndicator.enabled
view.backgroundColor = LightboxConfig.PageIndicator.separatorColor
return view
}()
let gradientColors = [UIColor(hex: "040404").withAlphaComponent(0.1), UIColor(hex: "040404")]
open weak var delegate: FooterViewDelegate?
// MARK: - Initializers
public init() {
super.init(frame: CGRect.zero)
backgroundColor = UIColor.clear
_ = addGradientLayer(gradientColors)
[pageLabel, infoLabel, separatorView].forEach { addSubview($0) }
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Helpers
func expand(_ expand: Bool) {
expand ? infoLabel.expand() : infoLabel.collapse()
}
func updatePage(_ page: Int, _ numberOfPages: Int) {
let text = "\(page)/\(numberOfPages)"
pageLabel.attributedText = NSAttributedString(string: text,
attributes: LightboxConfig.PageIndicator.textAttributes)
pageLabel.sizeToFit()
}
func updateText(_ text: String) {
infoLabel.fullText = text
if text.isEmpty {
_ = removeGradientLayer()
} else if !infoLabel.expanded {
_ = addGradientLayer(gradientColors)
}
}
open override func layoutSubviews() {
super.layoutSubviews()
do {
let bottomPadding: CGFloat
if #available(iOS 11, *) {
bottomPadding = safeAreaInsets.bottom
} else {
bottomPadding = 0
}
pageLabel.frame.origin = CGPoint(
x: (frame.width - pageLabel.frame.width) / 2,
y: frame.height - pageLabel.frame.height - 2 - bottomPadding
)
}
separatorView.frame = CGRect(
x: 0,
y: pageLabel.frame.minY - 2.5,
width: frame.width,
height: 0.5
)
infoLabel.frame.origin.y = separatorView.frame.minY - infoLabel.frame.height - 15
resizeGradientLayer()
}
}
// MARK: - LayoutConfigurable
extension FooterView: LayoutConfigurable {
@objc public func configureLayout() {
infoLabel.frame = CGRect(x: 17, y: 0, width: frame.width - 17 * 2, height: 35)
infoLabel.configureLayout()
}
}
extension FooterView: InfoLabelDelegate {
public func infoLabel(_ infoLabel: InfoLabel, didExpand expanded: Bool) {
_ = (expanded || infoLabel.fullText.isEmpty) ? removeGradientLayer() : addGradientLayer(gradientColors)
delegate?.footerView(self, didExpand: expanded)
}
}
+113
View File
@@ -0,0 +1,113 @@
import UIKit
protocol HeaderViewDelegate: class {
func headerView(_ headerView: HeaderView, didPressDeleteButton deleteButton: UIButton)
func headerView(_ headerView: HeaderView, didPressCloseButton closeButton: UIButton)
}
open class HeaderView: UIView {
open fileprivate(set) lazy var closeButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: LightboxConfig.CloseButton.text,
attributes: LightboxConfig.CloseButton.textAttributes)
let button = UIButton(type: .system)
button.setAttributedTitle(title, for: UIControl.State())
if let size = LightboxConfig.CloseButton.size {
button.frame.size = size
} else {
button.sizeToFit()
}
button.addTarget(self, action: #selector(closeButtonDidPress(_:)),
for: .touchUpInside)
if let image = LightboxConfig.CloseButton.image {
button.setBackgroundImage(image, for: UIControl.State())
}
button.isHidden = !LightboxConfig.CloseButton.enabled
return button
}()
open fileprivate(set) lazy var deleteButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: LightboxConfig.DeleteButton.text,
attributes: LightboxConfig.DeleteButton.textAttributes)
let button = UIButton(type: .system)
button.setAttributedTitle(title, for: .normal)
if let size = LightboxConfig.DeleteButton.size {
button.frame.size = size
} else {
button.sizeToFit()
}
button.addTarget(self, action: #selector(deleteButtonDidPress(_:)),
for: .touchUpInside)
if let image = LightboxConfig.DeleteButton.image {
button.setBackgroundImage(image, for: UIControl.State())
}
button.isHidden = !LightboxConfig.DeleteButton.enabled
return button
}()
weak var delegate: HeaderViewDelegate?
// MARK: - Initializers
public init() {
super.init(frame: CGRect.zero)
backgroundColor = UIColor.clear
[closeButton, deleteButton].forEach { addSubview($0) }
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
@objc func deleteButtonDidPress(_ button: UIButton) {
delegate?.headerView(self, didPressDeleteButton: button)
}
@objc func closeButtonDidPress(_ button: UIButton) {
delegate?.headerView(self, didPressCloseButton: button)
}
}
// MARK: - LayoutConfigurable
extension HeaderView: LayoutConfigurable {
@objc public func configureLayout() {
let topPadding: CGFloat
if #available(iOS 11, *) {
topPadding = safeAreaInsets.top
} else {
topPadding = 0
}
closeButton.frame.origin = CGPoint(
x: bounds.width - closeButton.frame.width - 17,
y: topPadding
)
deleteButton.frame.origin = CGPoint(
x: 17,
y: topPadding
)
}
}
+152
View File
@@ -0,0 +1,152 @@
import UIKit
public protocol InfoLabelDelegate: class {
func infoLabel(_ infoLabel: InfoLabel, didExpand expanded: Bool)
}
open class InfoLabel: UILabel {
lazy var tapGestureRecognizer: UITapGestureRecognizer = { [unowned self] in
let gesture = UITapGestureRecognizer()
gesture.addTarget(self, action: #selector(labelDidTap(_:)))
return gesture
}()
open var numberOfVisibleLines = 2
var ellipsis: String {
return "... \(LightboxConfig.InfoLabel.ellipsisText)"
}
open weak var delegate: InfoLabelDelegate?
fileprivate var shortText = ""
var fullText: String {
didSet {
shortText = truncatedText
updateText(fullText)
configureLayout()
}
}
var expandable: Bool {
return shortText != fullText
}
fileprivate(set) var expanded = false {
didSet {
delegate?.infoLabel(self, didExpand: expanded)
}
}
var truncatedText: String {
var truncatedText = fullText
guard numberOfLines(fullText) > numberOfVisibleLines else {
return truncatedText
}
// Perform quick "rough cut"
while numberOfLines(truncatedText) > numberOfVisibleLines * 2 {
truncatedText = String(truncatedText.prefix(truncatedText.count / 2))
}
// Capture the endIndex of truncatedText before appending ellipsis
var truncatedTextCursor = truncatedText.endIndex
truncatedText += ellipsis
// Remove characters ahead of ellipsis until the text is the right number of lines
while numberOfLines(truncatedText) > numberOfVisibleLines {
// To avoid "Cannot decrement before startIndex"
guard truncatedTextCursor > truncatedText.startIndex else {
break
}
truncatedTextCursor = truncatedText.index(before: truncatedTextCursor)
truncatedText.remove(at: truncatedTextCursor)
}
return truncatedText
}
// MARK: - Initialization
public init(text: String, expanded: Bool = false) {
self.fullText = text
super.init(frame: CGRect.zero)
numberOfLines = 0
updateText(text)
self.expanded = expanded
addGestureRecognizer(tapGestureRecognizer)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
@objc func labelDidTap(_ tapGestureRecognizer: UITapGestureRecognizer) {
shortText = truncatedText
expanded ? collapse() : expand()
}
func expand() {
frame.size.height = heightForString(fullText)
updateText(fullText)
expanded = expandable
}
func collapse() {
frame.size.height = heightForString(shortText)
updateText(shortText)
expanded = false
}
fileprivate func updateText(_ string: String) {
let textAttributes = LightboxConfig.InfoLabel.textAttributes
let attributedString = NSMutableAttributedString(string: string, attributes: textAttributes)
if let range = string.range(of: ellipsis) {
let ellipsisColor = LightboxConfig.InfoLabel.ellipsisColor
let ellipsisRange = NSRange(range, in: string)
attributedString.addAttribute(.foregroundColor, value: ellipsisColor, range: ellipsisRange)
}
attributedText = attributedString
}
// MARK: - Helper methods
fileprivate func heightForString(_ string: String) -> CGFloat {
return string.boundingRect(
with: CGSize(width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
attributes: [NSAttributedString.Key.font: font!],
context: nil).height
}
fileprivate func numberOfLines(_ string: String) -> Int {
let lineHeight = "A".size(withAttributes: [NSAttributedString.Key.font: font!]).height
let totalHeight = heightForString(string)
return Int(totalHeight / lineHeight)
}
}
// MARK: - LayoutConfigurable
extension InfoLabel: LayoutConfigurable {
@objc public func configureLayout() {
shortText = truncatedText
expanded ? expand() : collapse()
}
}
+31
View File
@@ -0,0 +1,31 @@
import UIKit
class LoadingIndicator: UIView {
var indicator: UIActivityIndicatorView!
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
backgroundColor = UIColor.darkGray
layer.cornerRadius = bounds.size.width / 2
clipsToBounds = true
alpha = 0
indicator = UIActivityIndicatorView()
indicator.style = .whiteLarge
indicator.startAnimating()
addSubview(indicator)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
indicator.center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2)
}
}
+243
View File
@@ -0,0 +1,243 @@
import UIKit
protocol PageViewDelegate: class {
func pageViewDidZoom(_ pageView: PageView)
func remoteImageDidLoad(_ image: UIImage?, imageView: UIImageView)
func pageView(_ pageView: PageView, didTouchPlayButton videoURL: URL)
func pageViewDidTouch(_ pageView: PageView)
}
class PageView: UIScrollView {
lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var playButton: UIButton = {
let button = UIButton(type: .custom)
button.frame.size = CGSize(width: 60, height: 60)
var buttonImage = AssetManager.image("lightbox_play")
// Note by Elvis Nuñez on Mon 22 Jun 08:06
// When using SPM you might find that assets are note included. This is a workaround to provide default assets
// under iOS 13 so using SPM can work without problems.
if #available(iOS 13.0, *) {
if buttonImage == nil {
buttonImage = UIImage(systemName: "play.circle.fill")
}
}
button.setBackgroundImage(buttonImage, for: UIControl.State())
button.addTarget(self, action: #selector(playButtonTouched(_:)), for: .touchUpInside)
button.tintColor = .white
button.layer.shadowOffset = CGSize(width: 1, height: 1)
button.layer.shadowColor = UIColor.gray.cgColor
button.layer.masksToBounds = false
button.layer.shadowOpacity = 0.8
return button
}()
lazy var loadingIndicator: UIView = LightboxConfig.makeLoadingIndicator()
var image: LightboxImage
var contentFrame = CGRect.zero
weak var pageViewDelegate: PageViewDelegate?
var hasZoomed: Bool {
return zoomScale != 1.0
}
// MARK: - Initializers
init(image: LightboxImage) {
self.image = image
super.init(frame: CGRect.zero)
configure()
fetchImage()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Configuration
func configure() {
addSubview(imageView)
updatePlayButton()
addSubview(loadingIndicator)
delegate = self
isMultipleTouchEnabled = true
minimumZoomScale = LightboxConfig.Zoom.minimumScale
maximumZoomScale = LightboxConfig.Zoom.maximumScale
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(scrollViewDoubleTapped(_:)))
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.numberOfTouchesRequired = 1
addGestureRecognizer(doubleTapRecognizer)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
addGestureRecognizer(tapRecognizer)
tapRecognizer.require(toFail: doubleTapRecognizer)
}
// MARK: - Update
func update(with image: LightboxImage) {
self.image = image
updatePlayButton()
fetchImage()
}
func updatePlayButton () {
if self.image.videoURL != nil && !subviews.contains(playButton) {
addSubview(playButton)
} else if self.image.videoURL == nil && subviews.contains(playButton) {
playButton.removeFromSuperview()
}
}
// MARK: - Fetch
private func fetchImage () {
loadingIndicator.alpha = 1
self.image.addImageTo(imageView) { [weak self] image in
guard let self = self else {
return
}
self.isUserInteractionEnabled = true
self.configureImageView()
self.pageViewDelegate?.remoteImageDidLoad(image, imageView: self.imageView)
UIView.animate(withDuration: 0.4) {
self.loadingIndicator.alpha = 0
}
}
}
// MARK: - Recognizers
@objc func scrollViewDoubleTapped(_ recognizer: UITapGestureRecognizer) {
let pointInView = recognizer.location(in: imageView)
let newZoomScale = zoomScale > minimumZoomScale
? minimumZoomScale
: maximumZoomScale
let width = contentFrame.size.width / newZoomScale
let height = contentFrame.size.height / newZoomScale
let x = pointInView.x - (width / 2.0)
let y = pointInView.y - (height / 2.0)
let rectToZoomTo = CGRect(x: x, y: y, width: width, height: height)
zoom(to: rectToZoomTo, animated: true)
}
@objc func viewTapped(_ recognizer: UITapGestureRecognizer) {
pageViewDelegate?.pageViewDidTouch(self)
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
loadingIndicator.center = imageView.center
playButton.center = imageView.center
}
func configureImageView() {
guard let image = imageView.image else {
centerImageView()
return
}
let imageViewSize = imageView.frame.size
let imageSize = image.size
let realImageViewSize: CGSize
if imageSize.width / imageSize.height > imageViewSize.width / imageViewSize.height {
realImageViewSize = CGSize(
width: imageViewSize.width,
height: imageViewSize.width / imageSize.width * imageSize.height)
} else {
realImageViewSize = CGSize(
width: imageViewSize.height / imageSize.height * imageSize.width,
height: imageViewSize.height)
}
imageView.frame = CGRect(origin: CGPoint.zero, size: realImageViewSize)
centerImageView()
}
func centerImageView() {
let boundsSize = contentFrame.size
var imageViewFrame = imageView.frame
if imageViewFrame.size.width < boundsSize.width {
imageViewFrame.origin.x = (boundsSize.width - imageViewFrame.size.width) / 2.0
} else {
imageViewFrame.origin.x = 0.0
}
if imageViewFrame.size.height < boundsSize.height {
imageViewFrame.origin.y = (boundsSize.height - imageViewFrame.size.height) / 2.0
} else {
imageViewFrame.origin.y = 0.0
}
imageView.frame = imageViewFrame
}
// MARK: - Action
@objc func playButtonTouched(_ button: UIButton) {
guard let videoURL = image.videoURL else { return }
pageViewDelegate?.pageView(self, didTouchPlayButton: videoURL as URL)
}
}
// MARK: - LayoutConfigurable
extension PageView: LayoutConfigurable {
@objc func configureLayout() {
contentFrame = frame
contentSize = frame.size
imageView.frame = frame
zoomScale = minimumZoomScale
configureImageView()
}
}
// MARK: - UIScrollViewDelegate
extension PageView: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerImageView()
pageViewDelegate?.pageViewDidZoom(self)
}
}
+12
View File
@@ -0,0 +1,12 @@
machine:
xcode:
version: "9.0"
dependencies:
override:
- rm -rf Carthage
- carthage update
test:
override:
- set -o pipefail && xcodebuild -project Lightbox.xcodeproj -scheme "Lightbox-iOS" -sdk iphonesimulator clean build
+18
View File
@@ -0,0 +1,18 @@
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var controller: UINavigationController = UINavigationController(rootViewController: ViewController())
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
window?.rootViewController = controller
window?.makeKeyAndVisible()
return true
}
}
@@ -0,0 +1,53 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo3.jpg"
"filename" : "photo1.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo1.jpg"
"filename" : "photo2.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo2.jpg"
"filename" : "photo3.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -3,21 +3,19 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>no.hyper.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
@@ -31,6 +29,15 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
+56
View File
@@ -0,0 +1,56 @@
import UIKit
import Lightbox
class ViewController: UIViewController {
lazy var showButton: UIButton = { [unowned self] in
let button = UIButton()
button.addTarget(self, action: #selector(showLightbox), for: .touchUpInside)
button.setTitle("Show me the lightbox", for: UIControl.State())
button.setTitleColor(UIColor(red:0.47, green:0.6, blue:0.13, alpha:1), for: UIControl.State())
button.titleLabel?.font = UIFont(name: "AvenirNextCondensed-DemiBold", size: 30)
button.frame = UIScreen.main.bounds
button.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
view.backgroundColor = UIColor.white
view.addSubview(showButton)
title = "Lightbox"
}
// MARK: - Action methods
@objc func showLightbox() {
let images = [
LightboxImage(
image: UIImage(named: "photo1")!,
text: "Photography is the science, art, application and practice of creating durable images by recording light or other electromagnetic radiation, either electronically by means of an image sensor, or chemically by means of a light-sensitive material such as photographic film"
),
LightboxImage(imageURL: URL(string: "https://via.placeholder.com/300.png/09f/fff")!),
LightboxImage(
image: UIImage(named: "photo2")!,
text: "Emoji 😍 (/ɪˈmoʊdʒi/; singular emoji, plural emoji or emojis;[4] from the Japanese 絵文字えもじ, pronounced [emodʑi]) are ideograms and smileys used in electronic messages and web pages. Emoji are used much like emoticons and exist in various genres, including facial expressions, common objects, places and types of weather 🌅☔️💦, and animals 🐶🐱",
videoURL: URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
),
LightboxImage(
image: UIImage(named: "photo3")!,
text: "A lightbox is a translucent surface illuminated from behind, used for situations where a shape laid upon the surface needs to be seen with high contrast."
)
]
let controller = LightboxController(images: images)
controller.dynamicBackground = true
present(controller, animated: true, completion: nil)
}
}