├── screen.png
├── FSImageViewer.bundle
├── en.lproj
│ └── Localizable.strings
├── es.lproj
│ └── Localizable.strings
├── fr.lproj
│ └── Localizable.strings
├── it.lproj
│ └── Localizable.strings
├── de.lproj
│ └── Localizable.strings
├── nl.lproj
│ └── Localizable.strings
└── ru.lproj
│ └── Localizable.strings
├── FSImageViewerDemo
├── de.lproj
│ └── InfoPlist.strings
├── en.lproj
│ └── InfoPlist.strings
├── es.lproj
│ └── InfoPlist.strings
├── fr.lproj
│ └── InfoPlist.strings
├── it.lproj
│ └── InfoPlist.strings
├── nl.lproj
│ └── InfoPlist.strings
├── ru.lproj
│ └── InfoPlist.strings
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Icon-76.png
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-76@2x.png
│ │ ├── Icon-Small.png
│ │ ├── Icon-Small-40.png
│ │ ├── Icon-Small@2x-1.png
│ │ ├── Icon-Small@2x.png
│ │ ├── Icon-Small@3x.png
│ │ ├── Icon-Small-40@2x.png
│ │ ├── Icon-Small-40@3x.png
│ │ ├── Icon-Small-40@2x-1.png
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ ├── Default@2x.png
│ │ ├── Default-568h@2x.png
│ │ └── Contents.json
├── main.m
├── FSAppDelegate.h
├── FSImageViewerDemo-Prefix.pch
├── FSDemoViewController.h
├── FSImageViewerDemo-Info.plist
├── FSDemoViewController.xib
├── FSDemoViewController.m
└── FSAppDelegate.m
├── FSImageViewerTests
├── en.lproj
│ └── InfoPlist.strings
├── Testimage.jpg
├── ReferenceImages_64
│ ├── FSImageViewTests
│ │ ├── testView@2x.png
│ │ ├── testEmptyView@2x.png
│ │ ├── testFailedView@2x.png
│ │ ├── testViewWithBackgroundColor@2x.png
│ │ └── testEmptyViewWithProgressViewColor@2x.png
│ ├── FSPlaceholderImagesTests
│ │ └── testView@2x.png
│ └── FSImageTitleViewTests
│ │ ├── testLongTitle@2x.png
│ │ ├── testNormalTitle@2x.png
│ │ └── testShortTitle@2x.png
├── FSImageViewerTests-Prefix.pch
├── FSImageViewerTests-Info.plist
├── FSTestImageHelper.h
├── FSTestImageHelper.m
├── FSPlaceholderImagesTests.m
├── FSBasicImageSourceTests.m
├── FSImageTitleViewTests.m
└── FSImageViewTests.m
├── .gitignore
├── FSImageViewer.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── FSImageViewer.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── FSImageViewerDemo.xcscheme
│ └── FSImageViewer.xcscheme
├── Podfile
├── .travis.yml
├── FSImageViewer.podspec
├── LICENSE
├── FSImageViewer
├── FSImageScrollView.h
├── FSImageViewer-Prefix.pch
├── FSPlaceholderImages.h
├── FSImageTitleView.h
├── FSTitleView.h
├── FSBasicImageSource.h
├── FSBasicImageSource.m
├── FSImage.h
├── FSImageViewer.h
├── FSImageSource.h
├── FSBasicImage.h
├── FSImageView.h
├── FSImageLoader.h
├── FSBasicImage.m
├── FSImageScrollView.m
├── FSImageViewerViewController.h
├── FSPlaceholderImages.m
├── FSImageLoader.m
├── FSImageTitleView.m
├── FSImageView.m
└── FSImageViewerViewController.m
└── README.md
/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/screen.png
--------------------------------------------------------------------------------
/FSImageViewer.bundle/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "of";
2 | "done" = "Done";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/es.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "de";
2 | "done" = "OK";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "de";
2 | "done" = "Ok";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/it.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "di";
2 | "done" = "Fine";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/de.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "von";
2 | "done" = "Fertig";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/nl.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "van";
2 | "done" = "Gereed";
--------------------------------------------------------------------------------
/FSImageViewer.bundle/ru.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "imageCounter" = "из";
2 | "done" = "Готово";
--------------------------------------------------------------------------------
/FSImageViewerDemo/de.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/es.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/fr.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/it.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/nl.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/ru.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FSImageViewerTests/Testimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/Testimage.jpg
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/LaunchImage.launchimage/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/LaunchImage.launchimage/Default@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testView@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testView@2x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x-1.png
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerDemo/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testEmptyView@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testEmptyView@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testFailedView@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testFailedView@2x.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Podfile.lock
2 | Pods
3 | FSImageViewer.xcodeproj/xcuserdata
4 | *.xccheckout
5 | FSImageViewer.xcodeproj/project.xcworkspace/xcuserdata
6 | FSImageViewer.xcworkspace/xcuserdata
7 | documentation
8 |
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSPlaceholderImagesTests/testView@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSPlaceholderImagesTests/testView@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testLongTitle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testLongTitle@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testNormalTitle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testNormalTitle@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testShortTitle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageTitleViewTests/testShortTitle@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testViewWithBackgroundColor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testViewWithBackgroundColor@2x.png
--------------------------------------------------------------------------------
/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testEmptyViewWithProgressViewColor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x2on/FSImageViewer/HEAD/FSImageViewerTests/ReferenceImages_64/FSImageViewTests/testEmptyViewWithProgressViewColor@2x.png
--------------------------------------------------------------------------------
/FSImageViewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FSImageViewer.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSImageViewerTests-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #ifdef __OBJC__
8 | #import
9 | #import
10 | #import
11 | #import
12 | #import
13 | #endif
14 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | platform :ios, '7.0'
4 | inhibit_all_warnings!
5 |
6 | pod 'AFNetworking', '~> 2.5'
7 | pod 'EGOCache', '~> 2.1'
8 | pod 'UAProgressView', '~> 0.1'
9 |
10 | target :FSImageViewerDemo, :exclusive => true do
11 | link_with ['FSImageViewer']
12 | end
13 |
14 | target :FSImageViewerTests, :exclusive => true do
15 | pod 'OCMock', '~> 3.1'
16 | pod 'FBSnapshotTestCase/Core', '~> 2.0'
17 | end
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode7
2 | language: objective-c
3 | before_install:
4 | - echo "Update CocoaPods"
5 | - gem install cocoapods
6 | - pod --version
7 | - brew update
8 | - brew outdated xctool || brew upgrade xctool
9 | script:
10 | - xctool -workspace FSImageViewer.xcworkspace -scheme FSImageViewer -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' clean build test
11 | - pod --version
12 | - pod spec lint FSImageViewer.podspec
--------------------------------------------------------------------------------
/FSImageViewerTests/FSImageViewerTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/FSImageViewer.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "FSImageViewer"
3 | s.version = "3.4"
4 | s.summary = "FSImageViewer is a photo viewer for iOS."
5 | s.homepage = "https://github.com/x2on/FSImageViewer"
6 | s.social_media_url = 'https://twitter.com/x2on'
7 | s.screenshot = 'https://raw.github.com/x2on/FSImageViewer/master/screen.png'
8 | s.license = { :type => 'MIT', :file => 'LICENSE' }
9 | s.author = { "Felix Schulze" => "code@felixschulze.de" }
10 | s.source = {
11 | :git => "https://github.com/x2on/FSImageViewer.git",
12 | :tag => s.version.to_s
13 | }
14 |
15 | s.platform = :ios, '7.0'
16 | s.requires_arc = true
17 |
18 | s.source_files = 'FSImageViewer/FS*.{h,m}'
19 | s.resources = 'FSImageViewer.bundle'
20 |
21 | s.framework = 'Foundation', 'UIKit', 'CoreGraphics', 'QuartzCore', 'Security', 'CFNetwork'
22 |
23 | s.dependency 'AFNetworking', '~> 2.5'
24 | s.dependency 'EGOCache', '~> 2.1'
25 | s.dependency 'UAProgressView', '~> 0.1'
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Felix Schulze
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/FSImageViewer/FSImageScrollView.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSImageViewer.h"
26 |
27 | @interface FSImageScrollView : UIScrollView
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageViewer-Prefix.pch:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #ifdef __OBJC__
26 | #import
27 | #import
28 | #endif
--------------------------------------------------------------------------------
/FSImageViewer/FSPlaceholderImages.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | @interface FSPlaceholderImages : NSObject
28 |
29 | + (UIImage * _Nonnull)errorImage;
30 |
31 | @end
--------------------------------------------------------------------------------
/FSImageViewer/FSImageTitleView.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 | #import "FSTitleView.h"
25 |
26 | @interface FSImageTitleView : UIView
27 |
28 | @property (strong, nonatomic) NSString *text;
29 | @property (assign, nonatomic) BOOL adjustsFontSizeToFitWidth;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSTestImageHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // FSTestImageHelper.h
3 | // FSImageViewer
4 | //
5 | // Created by Felix Schulze on 19.09.15.
6 | // Copyright © 2015 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #import
28 | #import
29 |
30 | @interface FSTestImageHelper : NSObject
31 |
32 | + (UIImage *)imageNamed:(NSString *)name;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/main.m:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | #import "FSAppDelegate.h"
28 |
29 | int main(int argc, char *argv[])
30 | {
31 | @autoreleasepool {
32 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([FSAppDelegate class]));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSAppDelegate.h:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | @interface FSAppDelegate : UIResponder
28 |
29 | @property(strong, nonatomic) UIWindow *window;
30 | @property(strong, nonatomic) UINavigationController *navigationController;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSImageViewerDemo-Prefix.pch:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | #ifndef __IPHONE_6_0
28 | #warning "This project uses features only available in iOS SDK 6.0 and later."
29 | #endif
30 |
31 | #ifdef __OBJC__
32 | #import
33 | #import
34 | #endif
35 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSDemoViewController.h:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import "FSImageViewerViewController.h"
27 |
28 | @interface FSDemoViewController : UIViewController
29 |
30 | @property(strong, nonatomic) FSImageViewerViewController *imageViewController;
31 |
32 | - (IBAction)openGallery;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/FSImageViewer/FSTitleView.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// FSTitleView represents an abstract UIView with a title and the image object.
26 | @protocol FSTitleView
27 |
28 | - (void)updateMetadata:(NSString*)text index:(NSInteger)index total:(NSInteger)total;
29 | - (void)hideView:(BOOL)value;
30 | - (BOOL)isHidden;
31 | - (void)adjustTextViewSize:(CGRect)imageViewControllerBounds;
32 |
33 | @end
--------------------------------------------------------------------------------
/FSImageViewer/FSBasicImageSource.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 9/04/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import "FSImageSource.h"
27 |
28 | /// FSBasicImageSource is a standard implementation of FSImageSource.
29 | @interface FSBasicImageSource : NSObject
30 |
31 | /// @param images array of FSImage objects
32 | - (instancetype _Nonnull)initWithImages:(NSArray>* _Nonnull)images;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSTestImageHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // FSTestImageHelper.m
3 | // FSImageViewer
4 | //
5 | // Created by Felix Schulze on 19.09.15.
6 | // Copyright © 2015 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #import "FSTestImageHelper.h"
28 |
29 | @implementation FSTestImageHelper
30 |
31 | + (UIImage *)imageNamed:(NSString *)name {
32 | NSString *extension = name.pathExtension ? name.pathExtension : @"png";
33 | NSString *fileName = name.stringByDeletingPathExtension;
34 | NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:fileName ofType:extension];
35 | return [UIImage imageWithContentsOfFile:imagePath];
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/FSImageViewer/FSBasicImageSource.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 9/04/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSBasicImageSource.h"
26 |
27 | @implementation FSBasicImageSource
28 |
29 | @synthesize images = _images;
30 | @synthesize numberOfImages = _numberOfImages;
31 |
32 | - (instancetype _Nonnull)initWithImages:(NSArray>* _Nonnull)images{
33 |
34 | if (self = [super init]) {
35 | _images = images;
36 | _numberOfImages = [images count];
37 | }
38 |
39 | return self;
40 |
41 | }
42 |
43 | - (id )objectAtIndexedSubscript:(NSUInteger)index {
44 | return _images[index];
45 | }
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSImageViewerDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIcons
12 |
13 | CFBundleIcons~ipad
14 |
15 | CFBundleIdentifier
16 | $(PRODUCT_BUNDLE_IDENTIFIER)
17 | CFBundleInfoDictionaryVersion
18 | 6.0
19 | CFBundleName
20 | ${PRODUCT_NAME}
21 | CFBundlePackageType
22 | APPL
23 | CFBundleShortVersionString
24 | 1.0
25 | CFBundleSignature
26 | ????
27 | CFBundleVersion
28 | 1.0
29 | LSRequiresIPhoneOS
30 |
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 | NSAppTransportSecurity
49 |
50 | NSAllowsArbitraryLoads
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImage.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// FSImage represents an abstract image object with URL, title and the image object.
26 | @protocol FSImage
27 |
28 | /// The remote image URL
29 | @property(strong, nonatomic, readonly) NSURL *URL;
30 | /// The title of the image - is displayed as overlay.
31 | @property(strong, nonatomic, readonly) NSString *title;
32 | /// The image size
33 | @property(assign, nonatomic) CGSize size;
34 | /// The UIImage representation - set directly if not from remote.
35 | @property(strong, nonatomic) UIImage *image;
36 | /// true if the image download failed.
37 | @property(assign, nonatomic, getter=didFail) BOOL failed;
38 |
39 | @end
--------------------------------------------------------------------------------
/FSImageViewerTests/FSPlaceholderImagesTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // FSPlaceholderImagesTests.m
3 | // FSImageViewerTests
4 | //
5 | // Created by Felix Schulze on 01.06.14.
6 | // Copyright (c) 2014 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #import
28 | #import
29 |
30 | #import "FSPlaceholderImages.h"
31 |
32 |
33 | @interface FSPlaceholderImagesTests : FBSnapshotTestCase
34 | @end
35 |
36 | @implementation FSPlaceholderImagesTests
37 |
38 | - (void)setUp {
39 | [super setUp];
40 |
41 | self.recordMode = NO;
42 | }
43 |
44 |
45 | - (void)testView {
46 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[FSPlaceholderImages errorImage]];
47 | FBSnapshotVerifyView(imageView, nil);
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-Small@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-Small@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-Small-40@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-Small-40@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-60@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-60@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "Icon-Small.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "Icon-Small@2x-1.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "Icon-Small-40.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-Small-40@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-76.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-76@2x.png",
73 | "scale" : "2x"
74 | }
75 | ],
76 | "info" : {
77 | "version" : 1,
78 | "author" : "xcode"
79 | },
80 | "properties" : {
81 | "pre-rendered" : true
82 | }
83 | }
--------------------------------------------------------------------------------
/FSImageViewer/FSImageViewer.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSImageViewerViewController.h"
26 | #import "FSImageScrollView.h"
27 | #import "FSImageView.h"
28 | #import "FSImageTitleView.h"
29 | #import "FSImageSource.h"
30 | #import "FSImage.h"
31 | #import "FSPlaceholderImages.h"
32 |
33 | #define kFSImageViewerToogleBarsNotificationKey @"FSImageViewerToggleBars"
34 | #define kFSImageViewerDidFinishedLoadingNotificationKey @"FSImageViewerDidFinishLoading"
35 |
36 | #ifndef FSImageViewerErrorPlaceholderImage
37 | #define FSImageViewerErrorPlaceholderImage [FSPlaceholderImages errorImage]
38 | #endif
39 |
40 | #ifndef kFSImageViewerImageGap
41 | #define kFSImageViewerImageGap 30
42 | #endif
43 |
44 | #ifndef kFSImageViewerZoomScale
45 | #define kFSImageViewerZoomScale 2.5
46 | #endif
--------------------------------------------------------------------------------
/FSImageViewer/FSImageSource.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | @protocol FSImage;
26 |
27 | /// FSImageSource is the data source for the images. For normal usage you can use FSBasicImageSource
28 | @protocol FSImageSource
29 |
30 | /// The array contains all image objects.
31 | @property(strong, nonatomic, readonly) NSArray> *images;
32 |
33 | /// The number of the image objects are stored in the images array.
34 | @property(assign, nonatomic, readonly) NSInteger numberOfImages;
35 |
36 | /// Must return image at the given index - with object subscription you can use it like `imageSource[1];
37 | /// @param index image index
38 | /// @return image at given index
39 | /// @warning index must be in the range of the images
40 | - (id )objectAtIndexedSubscript:(NSUInteger)index;
41 |
42 | @end
43 |
44 |
45 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "8.0",
8 | "subtype" : "736h",
9 | "scale" : "3x"
10 | },
11 | {
12 | "orientation" : "landscape",
13 | "idiom" : "iphone",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "8.0",
16 | "subtype" : "736h",
17 | "scale" : "3x"
18 | },
19 | {
20 | "orientation" : "portrait",
21 | "idiom" : "iphone",
22 | "extent" : "full-screen",
23 | "minimum-system-version" : "8.0",
24 | "subtype" : "667h",
25 | "scale" : "2x"
26 | },
27 | {
28 | "orientation" : "portrait",
29 | "idiom" : "iphone",
30 | "extent" : "full-screen",
31 | "minimum-system-version" : "7.0",
32 | "filename" : "Default@2x.png",
33 | "scale" : "2x"
34 | },
35 | {
36 | "extent" : "full-screen",
37 | "idiom" : "iphone",
38 | "subtype" : "retina4",
39 | "filename" : "Default-568h@2x.png",
40 | "minimum-system-version" : "7.0",
41 | "orientation" : "portrait",
42 | "scale" : "2x"
43 | },
44 | {
45 | "orientation" : "portrait",
46 | "idiom" : "ipad",
47 | "extent" : "full-screen",
48 | "minimum-system-version" : "7.0",
49 | "scale" : "1x"
50 | },
51 | {
52 | "orientation" : "landscape",
53 | "idiom" : "ipad",
54 | "extent" : "full-screen",
55 | "minimum-system-version" : "7.0",
56 | "scale" : "1x"
57 | },
58 | {
59 | "orientation" : "portrait",
60 | "idiom" : "ipad",
61 | "extent" : "full-screen",
62 | "minimum-system-version" : "7.0",
63 | "scale" : "2x"
64 | },
65 | {
66 | "orientation" : "landscape",
67 | "idiom" : "ipad",
68 | "extent" : "full-screen",
69 | "minimum-system-version" : "7.0",
70 | "scale" : "2x"
71 | }
72 | ],
73 | "info" : {
74 | "version" : 1,
75 | "author" : "xcode"
76 | }
77 | }
--------------------------------------------------------------------------------
/FSImageViewer/FSBasicImage.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 9/04/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSImageViewer.h"
26 |
27 | /// FSBasicImage is a standard implementation of FSImage. It can download images from an URL or use an image.
28 | @interface FSBasicImage : NSObject
29 |
30 | /// @param URL remote image URL
31 | /// @param name title of the image
32 | - (instancetype _Nonnull)initWithImageURL:(NSURL * _Nonnull)URL name:(NSString * _Nullable)name;
33 |
34 | /// @param URL remote image URL
35 | - (instancetype _Nonnull)initWithImageURL:(NSURL * _Nonnull)URL;
36 |
37 | /// @param image an UIImage representation of the image
38 | - (instancetype _Nonnull)initWithImage:(UIImage * _Nonnull)image;
39 |
40 | /// @param image an UIImage representation of the image
41 | /// @param name title of the image
42 | - (instancetype _Nonnull)initWithImage:(UIImage * _Nonnull)image name:(NSString * _Nullable)name;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageView.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import
27 | #import "FSImageSource.h"
28 | #import "FSImageLoader.h"
29 |
30 | @class FSImageScrollView, FSImageTitleView;
31 |
32 | @interface FSImageView : UIView
33 |
34 | @property(strong, nonatomic) id image;
35 | @property(strong, nonatomic, readonly) UIImageView *imageView;
36 | @property(strong, nonatomic, readonly) FSImageScrollView *scrollView;
37 | @property(assign, nonatomic) BOOL loading;
38 | @property(assign, nonatomic) BOOL rotationEnabled;
39 |
40 | - (void)killScrollViewZoom;
41 |
42 | - (void)layoutScrollViewAnimated:(BOOL)animated;
43 |
44 | - (void)prepareForReuse;
45 |
46 | - (void)changeBackgroundColor:(UIColor *)color;
47 |
48 | - (void)changeProgressViewColor:(UIColor *)color;
49 |
50 | - (void)rotateToOrientation:(UIInterfaceOrientation)orientation;
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageLoader.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 |
27 | NS_ASSUME_NONNULL_BEGIN
28 |
29 | /// Download remote images with AFNetworking
30 | @interface FSImageLoader : NSObject
31 |
32 | /// Timeout for remote image downloading - Default is 30 seconds
33 | @property(assign, nonatomic) NSTimeInterval timeoutInterval;
34 |
35 | /// Singleton getter
36 | + (FSImageLoader *)sharedInstance;
37 |
38 | /// Download remote images from url
39 | /// @param url remote image url
40 | /// @param imageBlock block for image or error
41 | - (void)loadImageForURL:(NSURL * _Nonnull)url progress:(void (^)(float progress))progress image:(void (^)(UIImage * __nullable image, NSError * __nullable error))imageBlock;
42 |
43 | /// Cancel all image requests
44 | - (void)cancelAllRequests;
45 |
46 | /// Cancel image request
47 | /// @param url remote image url
48 | - (void)cancelRequestForUrl:(NSURL *)url;
49 |
50 | NS_ASSUME_NONNULL_END
51 |
52 | @end
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSDemoViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/FSImageViewer/FSBasicImage.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 9/04/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSBasicImage.h"
26 |
27 | @implementation FSBasicImage
28 |
29 | @synthesize URL = _URL;
30 | @synthesize title = _title;
31 | @synthesize size = _size;
32 | @synthesize image = _image;
33 | @synthesize failed = _failed;
34 |
35 | - (instancetype)initWithImageURL:(NSURL *)aURL name:(NSString *)aName image:(UIImage *)aImage {
36 | self = [super init];
37 | if (self) {
38 | _URL = aURL;
39 | _title = aName;
40 | self.image = aImage;
41 |
42 | }
43 | return self;
44 | }
45 |
46 | - (instancetype)initWithImageURL:(NSURL *)aURL name:(NSString *)aName {
47 | return [self initWithImageURL:aURL name:aName image:nil];
48 | }
49 |
50 | - (instancetype)initWithImageURL:(NSURL *)aURL {
51 | return [self initWithImageURL:aURL name:nil image:nil];
52 | }
53 |
54 | - (instancetype)initWithImage:(UIImage *)aImage {
55 | return [self initWithImageURL:nil name:nil image:aImage];
56 | }
57 |
58 | - (instancetype)initWithImage:(UIImage *)aImage name:(NSString *)aName {
59 | return [self initWithImageURL:nil name:aName image:aImage];
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSBasicImageSourceTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // FSBasicImageSourceTests.m
3 | // FSImageViewer
4 | //
5 | // Created by Felix Schulze on 19.09.15.
6 | // Copyright © 2015 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #import "FSBasicImageSource.h"
28 | #import "FSImage.h"
29 | #import "FSBasicImage.h"
30 |
31 | @interface FSBasicImageSourceTests : XCTestCase
32 |
33 | @end
34 |
35 | @implementation FSBasicImageSourceTests
36 |
37 | - (void)testObjectSubscription {
38 | id imageMock = OCMProtocolMock(@protocol(FSImage));
39 | NSArray> *basicImageSource = @[imageMock];
40 | FSBasicImageSource *imageSource = [[FSBasicImageSource alloc] initWithImages:basicImageSource];
41 |
42 | XCTAssertEqual(imageSource.numberOfImages, 1);
43 | XCTAssertEqual(imageSource[0], imageMock);
44 | }
45 |
46 | - (void)testObjectSubscriptionWithBasicImage {
47 | FSBasicImage *basicImage = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://example.com"]];
48 | NSArray> *basicImageSource = @[basicImage];
49 | FSBasicImageSource *imageSource = [[FSBasicImageSource alloc] initWithImages:basicImageSource];
50 |
51 | XCTAssertEqual(imageSource.numberOfImages, 1);
52 | XCTAssertEqual(imageSource[0], basicImage);
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/FSImageViewer.xcworkspace/xcshareddata/xcschemes/FSImageViewerDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
67 |
68 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSImageTitleViewTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // FSImageViewerTests.m
3 | // FSImageViewerTests
4 | //
5 | // Created by Felix Schulze on 01.06.14.
6 | // Copyright (c) 2014 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #import "FSImageTitleView.h"
28 |
29 | @interface FSImageTitleViewTests : FBSnapshotTestCase
30 | @end
31 |
32 | @implementation FSImageTitleViewTests
33 |
34 | - (void)setUp {
35 | [super setUp];
36 |
37 | self.recordMode = NO;
38 | }
39 |
40 |
41 | - (void)testShortTitle {
42 | FSImageTitleView *view = [[FSImageTitleView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
43 | view.text = @"Some title";
44 | FBSnapshotVerifyView(view, nil);
45 | XCTAssertFalse(view.isHidden);
46 | }
47 |
48 | - (void)testNormalTitle {
49 | FSImageTitleView *view = [[FSImageTitleView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
50 | view.text = @"Some longer title with some lorem ipsum text";
51 | FBSnapshotVerifyView(view, nil);
52 | XCTAssertFalse(view.isHidden);
53 | }
54 |
55 | - (void)testLongTitle {
56 | FSImageTitleView *view = [[FSImageTitleView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
57 | view.text = @"Some longer title with some lorem ipsum text and some other lorem ipsum and another lorem ipsum text";
58 | FBSnapshotVerifyView(view, nil);
59 | XCTAssertFalse(view.isHidden);
60 | }
61 |
62 | - (void)testIsHiddenIfNoText {
63 | FSImageTitleView *view = [[FSImageTitleView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
64 | view.text = nil;
65 | XCTAssertTrue(view.isHidden);
66 | }
67 |
68 | - (void)testIsHiddenIfTextContainsOnlyWhitespace {
69 | FSImageTitleView *view = [[FSImageTitleView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
70 | view.text = @" ";
71 | XCTAssertTrue(view.isHidden);
72 | }
73 |
74 | @end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FSImageViewer [](https://travis-ci.org/x2on/FSImageViewer) [](http://cocoadocs.org/docsets/FSImageViewer/) [](http://cocoadocs.org/docsets/FSImageViewer/) [](http://opensource.org/licenses/MIT)
2 |
3 | 
4 |
5 | FSImageViewer is a photo viewer (gallery) for iOS.
6 |
7 | It's initially based on [EGOPhotoViewer](https://raw.github.com/enormego/PhotoViewer), but completely refactored to use ARC, [AFNetworking 2.5+](https://github.com/AFNetworking/AFNetworking) for remote image downloads and [EGOCache 2.1](https://github.com/enormego/EGOCache) for image caching.
8 |
9 | If you must use AFNetworking 1.3 you can use the 1.x version of FSImageViewer (https://github.com/x2on/FSImageViewer/tree/1.x)
10 |
11 | ## Install
12 | Using [CocoaPods](http://cocoapods.org/):
13 |
14 | `pod 'FSImageViewer', '~> 3.4'`
15 |
16 | ## Basic usage
17 |
18 | Create your image objects:
19 |
20 | ```objc
21 | FSBasicImage *firstPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://example.com/1.jpg"] name:@"Photo 1"];
22 | FSBasicImage *secondPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://example.com/2.jpg"] name:@"Photo 2"];
23 | ```
24 |
25 | And add them to the data source:
26 |
27 | ```objc
28 | FSBasicImageSource *photoSource = [[FSBasicImageSource alloc] initWithImages:@[firstPhoto, secondPhoto]];
29 | ```
30 |
31 | And create and show the view controller:
32 | ```objc
33 | FSImageViewerViewController *imageViewController = [[FSImageViewerViewController alloc] initWithImageSource:photoSource];
34 | [self.navigationController pushViewController:imageViewController animated:YES];
35 | ```
36 |
37 | If you like to use a modal view controller:
38 | ```objc
39 | FSImageViewerViewController *imageViewController = [[FSImageViewerViewController alloc] initWithImageSource:photoSource];
40 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:imageViewController];
41 | [self.navigationController presentViewController:navigationController animated:YES completion:nil];
42 | ```
43 |
44 | ## Advanced usage
45 |
46 | You can also create your own image class by implementing the `FSImage` protocol and your own datasource by implementing the `FSImageSource` protocol.
47 |
48 | ## Demo
49 |
50 | The demo project uses [CocoaPods](http://cocoapods.org/) for dependency management.
51 |
52 | Install dependencies:`pod install`
53 |
54 | ## System support
55 | iOS 7.0+ is currently supported.
56 |
57 | If you must support iOS 5.0+ you can use the 1.x version of FSImageViewer.
58 | If you must support iOS 6.0+ you can use the 2.x version of FSImageViewer.
59 |
60 | ## License
61 |
62 | FSImageViewer is available under the MIT license. See the LICENSE file for more info.
63 |
64 |
--------------------------------------------------------------------------------
/FSImageViewerTests/FSImageViewTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // FSImageViewTests.m
3 | // FSImageViewer
4 | //
5 | // Created by Felix Schulze on 19.09.15.
6 | // Copyright © 2015 Felix Schulze. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 | #import "FSImageView.h"
27 | #import "FSImage.h"
28 | #import "FSTestImageHelper.h"
29 |
30 | @interface FSImageViewTests : FBSnapshotTestCase
31 |
32 | @end
33 |
34 | @implementation FSImageViewTests
35 |
36 | - (void)setUp {
37 | [super setUp];
38 |
39 | self.recordMode = NO;
40 | }
41 |
42 | - (void)testEmptyView {
43 | FSImageView *view = [[FSImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
44 | FBSnapshotVerifyView(view, nil);
45 | }
46 |
47 | - (void)testEmptyViewWithProgressViewColor {
48 | FSImageView *view = [[FSImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
49 | [view changeProgressViewColor:[UIColor greenColor]];
50 | FBSnapshotVerifyView(view, nil);
51 | }
52 |
53 | - (void)testView {
54 | id mock = OCMProtocolMock(@protocol(FSImage));
55 | OCMStub([mock image]).andReturn([FSTestImageHelper imageNamed:@"Testimage.jpg"]);
56 | FSImageView *view = [[FSImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
57 | view.image = mock;
58 | FBSnapshotVerifyView(view, nil);
59 | }
60 |
61 | - (void)testViewWithBackgroundColor {
62 | id mock = OCMProtocolMock(@protocol(FSImage));
63 | OCMStub([mock image]).andReturn([FSTestImageHelper imageNamed:@"Testimage.jpg"]);
64 | FSImageView *view = [[FSImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
65 | view.image = mock;
66 | [view changeBackgroundColor:[UIColor greenColor]];
67 | FBSnapshotVerifyView(view, nil);
68 | }
69 |
70 | - (void)testFailedView {
71 | id mock = OCMProtocolMock(@protocol(FSImage));
72 | OCMStub([mock didFail]).andReturn(YES);
73 | FSImageView *view = [[FSImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
74 | view.image = mock;
75 | FBSnapshotVerifyView(view, nil);
76 | }
77 |
78 |
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSDemoViewController.m:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSDemoViewController.h"
26 | #import "FSBasicImage.h"
27 | #import "FSBasicImageSource.h"
28 |
29 | @implementation FSDemoViewController
30 |
31 | - (id)init {
32 | self = [super initWithNibName:@"FSDemoViewController" bundle:nil];
33 | if (self) {
34 | }
35 | return self;
36 | }
37 |
38 | - (void)viewDidLoad {
39 | [super viewDidLoad];
40 | }
41 |
42 | - (void)viewDidAppear:(BOOL)animated {
43 | [super viewDidAppear:animated];
44 |
45 | if (!_imageViewController) {
46 | [self openGallery];
47 | }
48 | }
49 |
50 | - (IBAction)openGallery {
51 | FSBasicImage *firstPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://farm8.staticflickr.com/7319/9668947331_3112b1fcca_b.jpg"] name:@"Photo by Brian Adamson"];
52 | FSBasicImage *secondPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://farm9.staticflickr.com/8023/6971840814_68614eba26_b.jpg"] name:@"Photo by Ben Fredericson (http://farm9.staticflickr.com/8023/6971840814_68614eba26_b.jpg)"];
53 | FSBasicImage *thirdPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://farm5.staticflickr.com/4094/4888398067_36e695177a_o.jpg"] name:@"Photo by digital cat (https://www.flickr.com/photos/14646075@N03/4888398067)"];
54 |
55 | FSBasicImage *failingPhoto = [[FSBasicImage alloc] initWithImageURL:[NSURL URLWithString:@"http://example.com/1.jpg"] name:@"Failure image"];
56 |
57 | FSBasicImageSource *photoSource = [[FSBasicImageSource alloc] initWithImages:@[firstPhoto, secondPhoto, thirdPhoto, failingPhoto]];
58 | self.imageViewController = [[FSImageViewerViewController alloc] initWithImageSource:photoSource];
59 |
60 | _imageViewController.delegate = self;
61 |
62 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
63 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:_imageViewController];
64 | [self.navigationController presentViewController:navigationController animated:YES completion:nil];
65 | }
66 | else {
67 | [self.navigationController pushViewController:_imageViewController animated:YES];
68 | }
69 | }
70 |
71 | - (void)imageViewerViewController:(FSImageViewerViewController *)imageViewerViewController didMoveToImageAtIndex:(NSInteger)index {
72 | NSLog(@"FSImageViewerViewController: %@ didMoveToImageAtIndex: %li",imageViewerViewController, (long)index);
73 | }
74 | @end
75 |
--------------------------------------------------------------------------------
/FSImageViewerDemo/FSAppDelegate.m:
--------------------------------------------------------------------------------
1 | // FSImageViewerDemo
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSAppDelegate.h"
26 | #import "FSDemoViewController.h"
27 |
28 | @implementation FSAppDelegate
29 |
30 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
31 | if (!getenv("UNIT_TEST")) {
32 | FSDemoViewController *viewController = [[FSDemoViewController alloc] init];
33 | self.navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
34 | }
35 | else {
36 | self.navigationController = [[UINavigationController alloc] initWithRootViewController:[[UIViewController alloc] init]];
37 | }
38 |
39 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
40 | self.window.rootViewController = _navigationController;
41 | [self.window makeKeyAndVisible];
42 |
43 | return YES;
44 | }
45 |
46 | - (void)applicationWillResignActive:(UIApplication *)application {
47 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
48 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
49 | }
50 |
51 | - (void)applicationDidEnterBackground:(UIApplication *)application {
52 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
53 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
54 | }
55 |
56 | - (void)applicationWillEnterForeground:(UIApplication *)application {
57 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
58 | }
59 |
60 | - (void)applicationDidBecomeActive:(UIApplication *)application {
61 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
62 | }
63 |
64 | - (void)applicationWillTerminate:(UIApplication *)application {
65 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
66 | }
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/FSImageViewer.xcworkspace/xcshareddata/xcschemes/FSImageViewer.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
72 |
73 |
79 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
97 |
98 |
99 |
100 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageScrollView.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSImageScrollView.h"
26 |
27 | @implementation FSImageScrollView
28 |
29 | - (instancetype)initWithFrame:(CGRect)frame {
30 | self = [super initWithFrame:frame];
31 | if (self) {
32 | self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
33 | self.scrollEnabled = NO;
34 | self.pagingEnabled = NO;
35 | self.clipsToBounds = NO;
36 | self.maximumZoomScale = 3.0f;
37 | self.minimumZoomScale = 1.0f;
38 | self.showsVerticalScrollIndicator = NO;
39 | self.showsHorizontalScrollIndicator = NO;
40 | self.bounces = YES;
41 | self.alwaysBounceVertical = NO;
42 | self.alwaysBounceHorizontal = NO;
43 | self.bouncesZoom = YES;
44 | self.scrollsToTop = NO;
45 | self.backgroundColor = [UIColor whiteColor];
46 | self.decelerationRate = UIScrollViewDecelerationRateFast;
47 | }
48 | return self;
49 | }
50 |
51 | - (void)zoomRectWithCenter:(CGPoint)center{
52 |
53 | if (self.zoomScale > 1.0f) {
54 | self.scrollEnabled = NO;
55 | [((FSImageView *)self.superview) killScrollViewZoom];
56 | return;
57 | }
58 | self.scrollEnabled = YES;
59 | CGRect rect;
60 | rect.size = CGSizeMake(self.frame.size.width / kFSImageViewerZoomScale, self.frame.size.height / kFSImageViewerZoomScale);
61 | rect.origin.x = MAX((center.x - (rect.size.width / 2.0f)), 0.0f);
62 | rect.origin.y = MAX((center.y - (rect.size.height / 2.0f)), 0.0f);
63 |
64 | CGRect frame = [self.superview convertRect:self.frame toView:self.superview];
65 | CGFloat borderX = frame.origin.x;
66 | CGFloat borderY = frame.origin.y;
67 |
68 | if (borderX > 0.0f && (center.x < borderX || center.x > self.frame.size.width - borderX)) {
69 |
70 | if (center.x < (self.frame.size.width / 2.0f)) {
71 | rect.origin.x += (borderX/kFSImageViewerZoomScale);
72 | } else {
73 | rect.origin.x -= ((borderX/kFSImageViewerZoomScale) + rect.size.width);
74 | }
75 | }
76 |
77 | if (borderY > 0.0f && (center.y < borderY || center.y > self.frame.size.height - borderY)) {
78 | if (center.y < (self.frame.size.height / 2.0f)) {
79 | rect.origin.y += (borderY/kFSImageViewerZoomScale);
80 | } else {
81 | rect.origin.y -= ((borderY/kFSImageViewerZoomScale) + rect.size.height);
82 | }
83 | }
84 |
85 | [self zoomToRect:rect animated:YES];
86 | }
87 |
88 | - (void)toggleBars{
89 | [[NSNotificationCenter defaultCenter] postNotificationName:kFSImageViewerToogleBarsNotificationKey object:nil];
90 | }
91 |
92 | #pragma mark - Touches
93 |
94 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
95 | [super touchesBegan:touches withEvent:event];
96 | }
97 |
98 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
99 | [super touchesEnded:touches withEvent:event];
100 | UITouch *touch = [touches anyObject];
101 |
102 | if (touch.tapCount == 1) {
103 | [self performSelector:@selector(toggleBars) withObject:nil afterDelay:.2];
104 | } else if (touch.tapCount == 2) {
105 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(toggleBars) object:nil];
106 | [self zoomRectWithCenter:[[touches anyObject] locationInView:self]];
107 | }
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageViewerViewController.h:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 | #import
25 | #import "FSImageViewer.h"
26 | #import "FSImageSource.h"
27 | #import "FSTitleView.h"
28 |
29 | NS_ASSUME_NONNULL_BEGIN
30 |
31 | @class FSImageViewerViewController;
32 |
33 | // Optional Delegate for getting current presented image index.
34 | @protocol FSImageViewerViewControllerDelegate
35 |
36 | @optional
37 |
38 | // Called if moved to the image at the given index.
39 | - (void)imageViewerViewController:(FSImageViewerViewController *)imageViewerViewController didMoveToImageAtIndex:(NSInteger)index;
40 |
41 | - (void)imageViewerViewController:(FSImageViewerViewController *)imageViewerViewController willDismissViewControllerAnimated:(BOOL)animated;
42 | - (void)imageViewerViewController:(FSImageViewerViewController *)imageViewerViewController didDismissViewControllerAnimated:(BOOL)animated;
43 |
44 | @end
45 |
46 | /// FSImageViewerViewController is an UIViewController which can present images.
47 | @interface FSImageViewerViewController : UIViewController
48 |
49 | /// @param imageSource image data source
50 | - (instancetype)initWithImageSource:(id )imageSource;
51 |
52 | /// @param imageSource image data source
53 | /// @param imageIndex the index of the first shown image
54 | - (instancetype)initWithImageSource:(id )imageSource imageIndex:(NSInteger)imageIndex;
55 |
56 | /// Image data source
57 | @property(strong, nonatomic, readonly) id imageSource;
58 |
59 | /// Title
60 | @property(strong, nonatomic, nullable) UIView* titleView;
61 |
62 | /// Optional Delegate
63 | @property(weak, nonatomic, nullable) id delegate;
64 |
65 | /// FSImageView array
66 | @property(strong, nonatomic, nullable) NSMutableArray *imageViews;
67 |
68 | /// Main scrollView
69 | @property(strong, nonatomic, nullable) UIScrollView *scrollView;
70 |
71 | /// Display a "x of y" images in the navigation title - Default is YES
72 | @property(assign, nonatomic) BOOL showNumberOfItemsInTitle;
73 |
74 | /// Disable image sharing - Default is NO
75 | @property(assign, nonatomic, getter = isSharingDisabled) BOOL sharingDisabled;
76 |
77 | /// Override rotation of images - Default is YES
78 | @property(assign, nonatomic, getter = isRotationEnabled) BOOL rotationEnabled;
79 |
80 | /// Override the background color when overlay is hidden - Default is black
81 | @property(strong, nonatomic, nullable) UIColor *backgroundColorHidden;
82 |
83 | /// Override the background color when overlay is visible - Default is white
84 | @property(strong, nonatomic, nullable) UIColor *backgroundColorVisible;
85 |
86 | /// Override the progressView color when overlay is hidden - Default is white
87 | @property(strong, nonatomic, nullable) UIColor *progressColorHidden;
88 |
89 | /// Override the progressView color when overlay is visible - Default is darkGrayColor
90 | @property(strong, nonatomic, nullable) UIColor *progressColorVisible;
91 |
92 | /// Used to add additional items to the "share" button
93 | @property(strong, nonatomic, nullable) NSArray* applicationActivities;
94 |
95 | /// Current index of the image displayed
96 | /// @return current index of the image displayed
97 | - (NSInteger)currentImageIndex;
98 |
99 | /// Move the FSImageView to the index
100 | /// @param index index move to
101 | /// @param animated should the movevement animated
102 | - (void)moveToImageAtIndex:(NSInteger)index animated:(BOOL)animated;
103 |
104 | NS_ASSUME_NONNULL_END
105 |
106 | @end
--------------------------------------------------------------------------------
/FSImageViewer/FSPlaceholderImages.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSPlaceholderImages.h"
26 |
27 | @implementation FSPlaceholderImages
28 |
29 | + (UIImage *)errorImage {
30 | UIImage *errorImage;
31 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(320, 480), NO, [[UIScreen mainScreen] scale]);
32 |
33 | UIColor *signColor = [UIColor colorWithRed:0.333 green:0.333 blue:0.333 alpha:1];
34 | UIColor *bangColor = [UIColor whiteColor];
35 |
36 | UIBezierPath *signPath = [UIBezierPath bezierPath];
37 | [signPath moveToPoint:CGPointMake(161.99, 183.24)];
38 | [signPath addLineToPoint:CGPointMake(102.02, 281.82)];
39 | [signPath addCurveToPoint:CGPointMake(102.02, 287.92) controlPoint1:CGPointMake(100.87, 283.71) controlPoint2:CGPointMake(100.87, 286.03)];
40 | [signPath addCurveToPoint:CGPointMake(107.57, 290.95) controlPoint1:CGPointMake(103.15, 289.78) controlPoint2:CGPointMake(105.27, 290.95)];
41 | [signPath addLineToPoint:CGPointMake(227.51, 290.95)];
42 | [signPath addCurveToPoint:CGPointMake(233.06, 287.92) controlPoint1:CGPointMake(229.79, 290.95) controlPoint2:CGPointMake(231.91, 289.78)];
43 | [signPath addCurveToPoint:CGPointMake(233.06, 281.82) controlPoint1:CGPointMake(234.19, 286.03) controlPoint2:CGPointMake(234.19, 283.71)];
44 | [signPath addLineToPoint:CGPointMake(173.1, 183.24)];
45 | [signPath addCurveToPoint:CGPointMake(167.54, 180.18) controlPoint1:CGPointMake(171.95, 181.36) controlPoint2:CGPointMake(169.82, 180.18)];
46 | [signPath addCurveToPoint:CGPointMake(161.99, 183.24) controlPoint1:CGPointMake(165.26, 180.18) controlPoint2:CGPointMake(163.14, 181.36)];
47 | [signPath closePath];
48 | signPath.miterLimit = 4;
49 |
50 | [signColor setFill];
51 | [signPath fill];
52 |
53 |
54 | UIBezierPath *bangPath = [UIBezierPath bezierPath];
55 | [bangPath moveToPoint:CGPointMake(164.98, 284.2)];
56 | [bangPath addCurveToPoint:CGPointMake(159.93, 276.55) controlPoint1:CGPointMake(162.12, 282.83) controlPoint2:CGPointMake(159.93, 279.52)];
57 | [bangPath addCurveToPoint:CGPointMake(171.15, 268.46) controlPoint1:CGPointMake(159.93, 271.03) controlPoint2:CGPointMake(165.7, 266.87)];
58 | [bangPath addCurveToPoint:CGPointMake(177.3, 276.63) controlPoint1:CGPointMake(174.83, 269.53) controlPoint2:CGPointMake(177.33, 272.85)];
59 | [bangPath addCurveToPoint:CGPointMake(173.05, 283.87) controlPoint1:CGPointMake(177.27, 279.84) controlPoint2:CGPointMake(175.88, 282.21)];
60 | [bangPath addCurveToPoint:CGPointMake(164.98, 284.2) controlPoint1:CGPointMake(170.88, 285.14) controlPoint2:CGPointMake(167.25, 285.29)];
61 | [bangPath closePath];
62 | [bangPath moveToPoint:CGPointMake(165.63, 262.4)];
63 | [bangPath addCurveToPoint:CGPointMake(163.76, 260.87) controlPoint1:CGPointMake(165.28, 262.2) controlPoint2:CGPointMake(164.43, 261.51)];
64 | [bangPath addCurveToPoint:CGPointMake(159.88, 234.65) controlPoint1:CGPointMake(161.41, 258.63) controlPoint2:CGPointMake(161.41, 258.65)];
65 | [bangPath addCurveToPoint:CGPointMake(159.09, 211.45) controlPoint1:CGPointMake(158.51, 213.31) controlPoint2:CGPointMake(158.5, 212.98)];
66 | [bangPath addCurveToPoint:CGPointMake(168.22, 206.75) controlPoint1:CGPointMake(160.4, 208) controlPoint2:CGPointMake(163.33, 206.49)];
67 | [bangPath addCurveToPoint:CGPointMake(175.26, 209.96) controlPoint1:CGPointMake(171.32, 206.91) controlPoint2:CGPointMake(173.71, 208)];
68 | [bangPath addCurveToPoint:CGPointMake(176.87, 215.27) controlPoint1:CGPointMake(176.59, 211.64) controlPoint2:CGPointMake(176.88, 212.59)];
69 | [bangPath addCurveToPoint:CGPointMake(174.75, 256.05) controlPoint1:CGPointMake(176.87, 218.18) controlPoint2:CGPointMake(175.02, 253.87)];
70 | [bangPath addCurveToPoint:CGPointMake(170.29, 262.27) controlPoint1:CGPointMake(174.41, 258.92) controlPoint2:CGPointMake(172.74, 261.24)];
71 | [bangPath addCurveToPoint:CGPointMake(165.63, 262.4) controlPoint1:CGPointMake(168.89, 262.85) controlPoint2:CGPointMake(166.58, 262.92)];
72 | [bangPath closePath];
73 | bangPath.miterLimit = 4;
74 |
75 | [bangColor setFill];
76 | [bangPath fill];
77 |
78 | errorImage = UIGraphicsGetImageFromCurrentImageContext();
79 | UIGraphicsEndImageContext();
80 | return errorImage;
81 | }
82 | @end
--------------------------------------------------------------------------------
/FSImageViewer/FSImageLoader.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import
27 | #import "FSImageLoader.h"
28 | #import "AFHTTPRequestOperation.h"
29 |
30 | @implementation FSImageLoader {
31 | NSMutableArray *runningRequests;
32 | }
33 |
34 | + (FSImageLoader *)sharedInstance {
35 | static FSImageLoader *sharedInstance = nil;
36 | static dispatch_once_t onceToken = 0;
37 | dispatch_once(&onceToken, ^{
38 | sharedInstance = [[FSImageLoader alloc] init];
39 | });
40 | return sharedInstance;
41 | }
42 |
43 | - (instancetype)init {
44 | self = [super init];
45 | if (self) {
46 | self.timeoutInterval = 30.0;
47 | runningRequests = [[NSMutableArray alloc] init];
48 | }
49 |
50 | return self;
51 | }
52 |
53 | - (void)dealloc {
54 | [self cancelAllRequests];
55 | }
56 |
57 | - (void)cancelAllRequests {
58 | for (AFHTTPRequestOperation *imageRequestOperation in runningRequests) {
59 | [imageRequestOperation cancel];
60 | }
61 | }
62 |
63 | - (void)cancelRequestForUrl:(NSURL *)aURL {
64 | for (AFHTTPRequestOperation *imageRequestOperation in runningRequests) {
65 | if ([imageRequestOperation.request.URL isEqual:aURL]) {
66 | [imageRequestOperation cancel];
67 | break;
68 | }
69 | }
70 | }
71 |
72 | - (void)loadImageForURL:(NSURL *)aURL progress:(void (^)(float progress))progress image:(void (^)(UIImage *image, NSError *error))imageBlock {
73 |
74 | if (!aURL) {
75 | NSError *error = [NSError errorWithDomain:@"de.felixschulze.fsimageloader" code:412 userInfo:@{
76 | NSLocalizedDescriptionKey : @"You must set a url"
77 | }];
78 | imageBlock(nil, error);
79 | };
80 |
81 | NSString *urlString = [[aURL absoluteString] copy];
82 | NSData *data = [urlString dataUsingEncoding:NSUTF8StringEncoding];
83 | uint8_t digest[CC_SHA1_DIGEST_LENGTH];
84 | CC_SHA1(data.bytes, (CC_LONG)data.length, digest);
85 | NSMutableString *urlStringSha1 = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
86 | for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
87 | [urlStringSha1 appendFormat:@"%02x", digest[i]];
88 | }
89 | NSString *cacheKey = [NSString stringWithFormat:@"FSImageLoader-%@", [urlStringSha1 copy]];
90 | UIImage *anImage = [[EGOCache globalCache] imageForKey:cacheKey];
91 |
92 | if (!anImage) {
93 | // Deprecated cacheKey
94 | NSString *deprecatedCacheKey = [NSString stringWithFormat:@"FSImageLoader-%lu", (unsigned long) [[aURL description] hash]];
95 | anImage = [[EGOCache globalCache] imageForKey:deprecatedCacheKey];
96 | }
97 |
98 |
99 | if (anImage) {
100 | if (imageBlock) {
101 | imageBlock(anImage, nil);
102 | }
103 | }
104 | else {
105 | [self cancelRequestForUrl:aURL];
106 |
107 | NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:aURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:_timeoutInterval];
108 | AFHTTPRequestOperation *imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
109 | imageRequestOperation.responseSerializer = [AFImageResponseSerializer serializer];
110 | [runningRequests addObject:imageRequestOperation];
111 | __weak AFHTTPRequestOperation *imageRequestOperationForBlock = imageRequestOperation;
112 |
113 | [imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
114 | UIImage *image = responseObject;
115 | [[EGOCache globalCache] setImage:image forKey:cacheKey];
116 | if (imageBlock) {
117 | imageBlock(image, nil);
118 | }
119 | [runningRequests removeObject:imageRequestOperationForBlock];
120 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
121 | if (imageBlock) {
122 | imageBlock(nil, error);
123 | }
124 | [runningRequests removeObject:imageRequestOperationForBlock];
125 | }];
126 |
127 | [imageRequestOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
128 | if (progress) {
129 | progress((float)totalBytesRead / totalBytesExpectedToRead);
130 | }
131 | }];
132 |
133 | [imageRequestOperation start];
134 | }
135 | }
136 |
137 | @end
--------------------------------------------------------------------------------
/FSImageViewer/FSImageTitleView.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import "FSImageTitleView.h"
27 |
28 | @implementation FSImageTitleView {
29 | UILabel *textLabel;
30 | BOOL hidden;
31 | }
32 |
33 | - (instancetype)initWithFrame:(CGRect)frame {
34 | if ((self = [super initWithFrame:frame])) {
35 |
36 | self.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.3f];
37 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
38 |
39 | textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 0.0f, self.frame.size.width - 40.0f, 40.0f)];
40 | textLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
41 | textLabel.numberOfLines = 0;
42 | textLabel.lineBreakMode = NSLineBreakByWordWrapping;
43 | textLabel.backgroundColor = [UIColor clearColor];
44 | textLabel.textAlignment = NSTextAlignmentCenter;
45 | textLabel.textColor = [UIColor whiteColor];
46 | textLabel.shadowColor = [UIColor blackColor];
47 | textLabel.shadowOffset = CGSizeMake(0.0f, 1.0f);
48 | [self addSubview:textLabel];
49 | }
50 | return self;
51 | }
52 |
53 | - (void)layoutSubviews {
54 | textLabel.frame = CGRectMake(20.0f, 0.0f, self.frame.size.width - 40.0f, 40.0f);
55 | [self setNeedsDisplay];
56 | }
57 |
58 | - (void)drawRect:(CGRect)rect {
59 | CGContextRef ctx = UIGraphicsGetCurrentContext();
60 | [[UIColor colorWithWhite:1.0f alpha:0.8f] setStroke];
61 | CGContextMoveToPoint(ctx, 0.0f, 0.0f);
62 | CGContextAddLineToPoint(ctx, self.frame.size.width, 0.0f);
63 | CGContextStrokePath(ctx);
64 | }
65 |
66 |
67 |
68 | - (void)setText:(NSString *)text {
69 | _text = text;
70 | textLabel.font = nil;
71 | if (_text == nil || [_text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 0) {
72 | textLabel.text = nil;
73 | self.hidden = YES;
74 | }
75 | else {
76 | textLabel.text = _text;
77 | self.hidden = NO;
78 | if (!_adjustsFontSizeToFitWidth) {
79 | [self adjustFontSizeToFit];
80 | }
81 | }
82 | }
83 |
84 | - (void)updateMetadata:(NSString *)text index:(NSInteger)index total:(NSInteger)total {
85 | self.text = text;
86 | }
87 |
88 | - (void) setAdjustsFontSizeToFitWidth:(BOOL)adjustsFontSizeToFitWidth {
89 | textLabel.adjustsFontSizeToFitWidth = adjustsFontSizeToFitWidth;
90 | _adjustsFontSizeToFitWidth = adjustsFontSizeToFitWidth;
91 | }
92 |
93 | - (void)hideView:(BOOL)value {
94 | if (hidden == value) {
95 | return;
96 | }
97 |
98 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
99 | [UIView animateWithDuration:0.3f animations:^{
100 | self.alpha = value ? 0.0f : 1.0f;
101 | }];
102 | hidden = value;
103 | }
104 | else {
105 | if (value) {
106 | [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
107 | self.frame = CGRectMake(0.0f, self.superview.frame.size.height, self.frame.size.width, self.frame.size.height);
108 | } completion:nil];
109 | }
110 | else {
111 | [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
112 | self.frame = CGRectMake(0.0f, self.superview.frame.size.height - self.frame.size.height, self.frame.size.width, self.frame.size.height);
113 | } completion:nil];
114 | }
115 | }
116 | hidden = value;
117 | }
118 |
119 | - (void)setHidden:(BOOL)aHidden {
120 | hidden = aHidden;
121 | }
122 |
123 | - (BOOL)isHidden {
124 | return hidden;
125 | }
126 |
127 | - (void) adjustTextViewSize:(CGRect)imageViewControllerBounds {
128 | self.frame = CGRectMake(0.0f, imageViewControllerBounds.size.height - 40.0f, imageViewControllerBounds.size.width, 40.0f);
129 | }
130 |
131 | - (void)adjustFontSizeToFit {
132 |
133 | for (int i = textLabel.font.pointSize; i>textLabel.minimumScaleFactor * textLabel.font.pointSize; i--) {
134 |
135 | UIFont *font = [UIFont fontWithName:textLabel.font.fontName size:(CGFloat)i];
136 | NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:textLabel.text attributes:@{NSFontAttributeName: font}];
137 |
138 | CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
139 |
140 | if (rectSize.size.height <= self.frame.size.height) {
141 | textLabel.font = [UIFont fontWithName:textLabel.font.fontName size:(CGFloat)i];
142 | break;
143 | }
144 | }
145 | }
146 |
147 | @end
148 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageView.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 | #import
25 | #import "FSImageView.h"
26 | #import "FSPlaceholderImages.h"
27 | #import "FSImageScrollView.h"
28 |
29 | #define ZOOM_VIEW_TAG 0x101
30 | #define MB_FILE_SIZE 1024*1024
31 |
32 | @interface RotateGesture : UIRotationGestureRecognizer {
33 | }
34 | @end
35 |
36 | @implementation RotateGesture
37 | - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)gesture {
38 | return NO;
39 | }
40 |
41 | - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer {
42 | return YES;
43 | }
44 | @end
45 |
46 | @interface FSImageView()
47 |
48 | @property (nonatomic, strong) UAProgressView *progressView;
49 |
50 | @end
51 |
52 | @implementation FSImageView {
53 | CGFloat beginRadians;
54 | }
55 |
56 | - (instancetype)initWithFrame:(CGRect)frame {
57 | if ((self = [super initWithFrame:frame])) {
58 |
59 | self.backgroundColor = [UIColor whiteColor];
60 | self.userInteractionEnabled = NO;
61 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
62 | self.opaque = YES;
63 | self.rotationEnabled = YES;
64 |
65 | FSImageScrollView *scrollView = [[FSImageScrollView alloc] initWithFrame:self.bounds];
66 | scrollView.backgroundColor = [UIColor whiteColor];
67 | scrollView.opaque = YES;
68 | scrollView.delegate = self;
69 | [self addSubview:scrollView];
70 | _scrollView = scrollView;
71 |
72 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
73 | imageView.opaque = YES;
74 | imageView.contentMode = UIViewContentModeScaleAspectFit;
75 | imageView.tag = ZOOM_VIEW_TAG;
76 | [_scrollView addSubview:imageView];
77 | _imageView = imageView;
78 |
79 | self.progressView = [[UAProgressView alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.frame) / 2) - 22.0f, CGRectGetHeight(self.frame) / 2 - 22.0f, 44.0f, 44.0f)];
80 |
81 | _progressView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
82 | [self addSubview:_progressView];
83 |
84 | RotateGesture *gesture = [[RotateGesture alloc] initWithTarget:self action:@selector(rotate:)];
85 | [self addGestureRecognizer:gesture];
86 |
87 | }
88 | return self;
89 | }
90 |
91 | - (void)dealloc {
92 | if (_image) {
93 | [[FSImageLoader sharedInstance] cancelRequestForUrl:self.image.URL];
94 | }
95 | }
96 |
97 |
98 | - (void)layoutSubviews {
99 | [super layoutSubviews];
100 |
101 | if (_scrollView.zoomScale == 1.0f) {
102 | [self layoutScrollViewAnimated:YES];
103 | }
104 |
105 | }
106 |
107 | - (void)setImage:(id )aImage {
108 |
109 | if (!aImage) {
110 | return;
111 | }
112 | if ([aImage isEqual:_image]) {
113 | return;
114 | }
115 | if (_image != nil) {
116 | [[FSImageLoader sharedInstance] cancelRequestForUrl:_image.URL];
117 | }
118 |
119 | _image = aImage;
120 |
121 | if (_image.image) {
122 | _imageView.image = _image.image;
123 |
124 | }
125 | else {
126 |
127 | if ([_image.URL isFileURL]) {
128 |
129 | NSError *error = nil;
130 | NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[_image.URL path] error:&error];
131 | NSInteger fileSize = [[attributes objectForKey:NSFileSize] integerValue];
132 |
133 | if (fileSize >= MB_FILE_SIZE) {
134 | _progressView.hidden = NO;
135 | [_progressView setProgress:0.5 animated:YES];
136 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
137 |
138 | UIImage *image = nil;
139 | NSData *data = [NSData dataWithContentsOfURL:self.image.URL];
140 | if (!data) {
141 | [self handleFailedImage];
142 | } else {
143 | image = [UIImage imageWithData:data];
144 | }
145 |
146 | dispatch_async(dispatch_get_main_queue(), ^{
147 | _progressView.hidden = YES;
148 | if (image != nil) {
149 | [self setupImageViewWithImage:image];
150 | }
151 |
152 | });
153 | });
154 |
155 | }
156 | else {
157 | self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:self.image.URL]];
158 | }
159 |
160 | }
161 | else {
162 | _progressView.hidden = NO;
163 | __weak FSImageView *weakSelf = self;
164 | [[FSImageLoader sharedInstance] loadImageForURL:_image.URL progress:^(float progress) {
165 | [weakSelf.progressView setProgress:progress animated:YES];
166 | }image:^(UIImage *image, NSError *error) {
167 | __strong FSImageView *strongSelf = weakSelf;
168 | if (!error) {
169 | strongSelf.image.image = image;
170 | [strongSelf setupImageViewWithImage:image];
171 | }
172 | else {
173 | [strongSelf handleFailedImage];
174 | }
175 | }];
176 | }
177 |
178 | }
179 |
180 | if (_imageView.image) {
181 | _progressView.hidden = YES;
182 | self.userInteractionEnabled = YES;
183 | _loading = NO;
184 |
185 | [[NSNotificationCenter defaultCenter] postNotificationName:kFSImageViewerDidFinishedLoadingNotificationKey object:@{
186 | @"image" : self.image,
187 | @"failed" : @(NO)
188 | }];
189 |
190 | } else {
191 | _loading = YES;
192 | self.userInteractionEnabled = NO;
193 | }
194 | [self layoutScrollViewAnimated:NO];
195 | }
196 |
197 | - (void)setupImageViewWithImage:(UIImage *)aImage {
198 | if (!aImage) {
199 | return;
200 | }
201 |
202 | _loading = NO;
203 | _progressView.hidden = YES;
204 | _imageView.image = aImage;
205 | [self layoutScrollViewAnimated:NO];
206 |
207 | [[self layer] addAnimation:[self fadeAnimation] forKey:@"opacity"];
208 | self.userInteractionEnabled = YES;
209 |
210 | [[NSNotificationCenter defaultCenter] postNotificationName:kFSImageViewerDidFinishedLoadingNotificationKey object:@{
211 | @"image" : self.image,
212 | @"failed" : @(NO)
213 | }];
214 | }
215 |
216 | - (void)prepareForReuse {
217 | self.tag = -1;
218 | }
219 |
220 | - (void)changeBackgroundColor:(UIColor *)color {
221 | self.backgroundColor = color;
222 | self.imageView.backgroundColor = color;
223 | self.scrollView.backgroundColor = color;
224 | }
225 |
226 | - (void)changeProgressViewColor:(UIColor *)color {
227 | _progressView.tintColor = color;
228 | }
229 |
230 |
231 | - (void)handleFailedImage {
232 |
233 | _imageView.image = FSImageViewerErrorPlaceholderImage;
234 | _image.failed = YES;
235 | [self layoutScrollViewAnimated:NO];
236 | self.userInteractionEnabled = NO;
237 | _progressView.hidden = YES;
238 | [[NSNotificationCenter defaultCenter] postNotificationName:kFSImageViewerDidFinishedLoadingNotificationKey object:@{
239 | @"image" : self.image,
240 | @"failed" : @(YES)
241 | }];
242 | }
243 |
244 | - (void)resetBackgroundColors {
245 | self.backgroundColor = [UIColor whiteColor];
246 | self.superview.backgroundColor = self.backgroundColor;
247 | self.superview.superview.backgroundColor = self.backgroundColor;
248 | }
249 |
250 |
251 | #pragma mark - Layout
252 |
253 | - (void)rotateToOrientation:(UIInterfaceOrientation)orientation {
254 |
255 | if (self.scrollView.zoomScale > 1.0f) {
256 |
257 | CGFloat height, width;
258 | height = MIN(CGRectGetHeight(self.imageView.frame) + self.imageView.frame.origin.x, CGRectGetHeight(self.bounds));
259 | width = MIN(CGRectGetWidth(self.imageView.frame) + self.imageView.frame.origin.y, CGRectGetWidth(self.bounds));
260 | self.scrollView.frame = CGRectMake((self.bounds.size.width / 2) - (width / 2), (self.bounds.size.height / 2) - (height / 2), width, height);
261 |
262 | } else {
263 |
264 | [self layoutScrollViewAnimated:NO];
265 |
266 | }
267 | }
268 |
269 | - (void)layoutScrollViewAnimated:(BOOL)animated {
270 |
271 | if (!_imageView.image) {
272 | return;
273 | }
274 |
275 | if (animated) {
276 | [UIView beginAnimations:nil context:NULL];
277 | [UIView setAnimationDuration:0.0001];
278 | }
279 |
280 | CGFloat hfactor = self.imageView.image.size.width / self.frame.size.width;
281 | CGFloat vfactor = self.imageView.image.size.height / self.frame.size.height;
282 |
283 | CGFloat factor = MAX(hfactor, vfactor);
284 |
285 | CGFloat newWidth = (int) (self.imageView.image.size.width / factor);
286 | CGFloat newHeight = (int) (self.imageView.image.size.height / factor);
287 |
288 | CGFloat leftOffset = (int) ((self.frame.size.width - newWidth) / 2);
289 | CGFloat topOffset = (int) ((self.frame.size.height - newHeight) / 2);
290 |
291 | self.scrollView.frame = CGRectMake(leftOffset, topOffset, newWidth, newHeight);
292 | self.scrollView.layer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
293 | self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
294 | self.scrollView.contentOffset = CGPointMake(0.0f, 0.0f);
295 | self.imageView.frame = self.scrollView.bounds;
296 |
297 | if (animated) {
298 | [UIView commitAnimations];
299 | }
300 | }
301 |
302 | #pragma mark - Animation
303 |
304 | - (CABasicAnimation *)fadeAnimation {
305 |
306 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
307 | animation.fromValue = [NSNumber numberWithFloat:0.0f];
308 | animation.toValue = [NSNumber numberWithFloat:1.0f];
309 | animation.duration = .3f;
310 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
311 |
312 | return animation;
313 | }
314 |
315 | #pragma mark - UIScrollViewDelegate
316 |
317 | - (void)killZoomAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
318 |
319 | if ([finished boolValue]) {
320 |
321 | [self.scrollView setZoomScale:1.0f animated:NO];
322 | self.imageView.frame = self.scrollView.bounds;
323 | [self layoutScrollViewAnimated:NO];
324 |
325 | }
326 |
327 | }
328 |
329 | - (void)killScrollViewZoom {
330 |
331 | if (!self.scrollView.zoomScale > 1.0f) return;
332 |
333 | if (!self.imageView.image) {
334 | return;
335 | }
336 |
337 | [UIView beginAnimations:nil context:NULL];
338 | [UIView setAnimationDuration:0.3];
339 | [UIView setAnimationDidStopSelector:@selector(killZoomAnimationDidStop:finished:context:)];
340 | [UIView setAnimationDelegate:self];
341 |
342 |
343 | CGFloat hfactor = self.imageView.image.size.width / self.frame.size.width;
344 | CGFloat vfactor = self.imageView.image.size.height / self.frame.size.height;
345 |
346 | CGFloat factor = MAX(hfactor, vfactor);
347 |
348 | CGFloat newWidth = (int) (self.imageView.image.size.width / factor);
349 | CGFloat newHeight = (int) (self.imageView.image.size.height / factor);
350 |
351 | CGFloat leftOffset = (int) ((self.frame.size.width - newWidth) / 2);
352 | CGFloat topOffset = (int) ((self.frame.size.height - newHeight) / 2);
353 |
354 | self.scrollView.frame = CGRectMake(leftOffset, topOffset, newWidth, newHeight);
355 | self.imageView.frame = self.scrollView.bounds;
356 |
357 | [UIView commitAnimations];
358 |
359 | }
360 |
361 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
362 | return [self.scrollView viewWithTag:ZOOM_VIEW_TAG];
363 | }
364 |
365 | - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
366 |
367 | if (scrollView.zoomScale > 1.0f) {
368 |
369 | CGFloat height;
370 | CGFloat width;
371 |
372 | if (CGRectGetMaxX(self.imageView.frame) > self.bounds.size.width) {
373 | width = CGRectGetWidth(self.bounds);
374 | } else {
375 | width = CGRectGetMaxX(self.imageView.frame);
376 | }
377 |
378 | if (CGRectGetMaxY(self.imageView.frame) > self.bounds.size.height) {
379 | height = CGRectGetHeight(self.bounds);
380 | } else {
381 | height = CGRectGetMaxY(self.imageView.frame);
382 | }
383 |
384 | CGRect frame = self.scrollView.frame;
385 | self.scrollView.frame = CGRectMake((self.bounds.size.width / 2) - (width / 2), (self.bounds.size.height / 2) - (height / 2), width, height);
386 | self.scrollView.layer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
387 | if (!CGRectEqualToRect(frame, self.scrollView.frame)) {
388 |
389 | CGFloat offsetY, offsetX;
390 |
391 | if (frame.origin.y < self.scrollView.frame.origin.y) {
392 | offsetY = self.scrollView.contentOffset.y - (self.scrollView.frame.origin.y - frame.origin.y);
393 | } else {
394 | offsetY = self.scrollView.contentOffset.y - (frame.origin.y - self.scrollView.frame.origin.y);
395 | }
396 |
397 | if (frame.origin.x < self.scrollView.frame.origin.x) {
398 | offsetX = self.scrollView.contentOffset.x - (self.scrollView.frame.origin.x - frame.origin.x);
399 | } else {
400 | offsetX = self.scrollView.contentOffset.x - (frame.origin.x - self.scrollView.frame.origin.x);
401 | }
402 |
403 | if (offsetY < 0) offsetY = 0;
404 | if (offsetX < 0) offsetX = 0;
405 |
406 | self.scrollView.contentOffset = CGPointMake(offsetX, offsetY);
407 | self.scrollView.scrollEnabled = YES;
408 | }
409 |
410 | } else {
411 | [self layoutScrollViewAnimated:YES];
412 | self.scrollView.scrollEnabled = NO;
413 | }
414 | }
415 |
416 | #pragma mark - RotateGesture
417 |
418 | - (void)rotate:(UIRotationGestureRecognizer *)gesture {
419 |
420 | if (!_rotationEnabled) {
421 | return;
422 | }
423 | if (gesture.state == UIGestureRecognizerStateBegan) {
424 | [self.layer removeAllAnimations];
425 | beginRadians = gesture.rotation;
426 | self.layer.transform = CATransform3DMakeRotation(beginRadians, 0.0f, 0.0f, 1.0f);
427 |
428 | }
429 | else if (gesture.state == UIGestureRecognizerStateChanged) {
430 | self.layer.transform = CATransform3DMakeRotation((beginRadians + gesture.rotation), 0.0f, 0.0f, 1.0f);
431 | }
432 | else {
433 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
434 | animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
435 | animation.duration = 0.3f;
436 | animation.removedOnCompletion = NO;
437 | animation.fillMode = kCAFillModeForwards;
438 | animation.delegate = self;
439 | [animation setValue:[NSNumber numberWithInt:202] forKey:@"AnimationType"];
440 | [self.layer addAnimation:animation forKey:@"RotateAnimation"];
441 | }
442 | }
443 |
444 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
445 |
446 | if (flag) {
447 | if ([[anim valueForKey:@"AnimationType"] integerValue] == 101) {
448 | [self resetBackgroundColors];
449 | } else if ([[anim valueForKey:@"AnimationType"] integerValue] == 202) {
450 | self.layer.transform = CATransform3DIdentity;
451 | }
452 | }
453 | }
454 |
455 | #pragma mark - Bars
456 |
457 | - (void)toggleBars {
458 | [[NSNotificationCenter defaultCenter] postNotificationName:kFSImageViewerToogleBarsNotificationKey object:nil];
459 | }
460 |
461 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
462 | [super touchesEnded:touches withEvent:event];
463 | UITouch *touch = [touches anyObject];
464 |
465 | if (touch.tapCount == 1) {
466 | [self performSelector:@selector(toggleBars) withObject:nil afterDelay:.2];
467 | }
468 | }
469 |
470 |
471 | @end
472 |
--------------------------------------------------------------------------------
/FSImageViewer/FSImageViewerViewController.m:
--------------------------------------------------------------------------------
1 | // FSImageViewer
2 | //
3 | // Created by Felix Schulze on 8/26/2013.
4 | // Copyright 2013 Felix Schulze. All rights reserved.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "FSImageViewerViewController.h"
26 | #import "FSImageTitleView.h"
27 |
28 | @interface FSImageViewerViewController ()
29 |
30 | @end
31 |
32 | @implementation FSImageViewerViewController {
33 | NSInteger pageIndex;
34 | NSInteger currentPageIndex;
35 | BOOL rotating;
36 | BOOL barsHidden;
37 | BOOL statusBarHidden;
38 | UIBarButtonItem *shareButton;
39 | }
40 |
41 | - (instancetype)initWithImageSource:(id )aImageSource {
42 | return [self initWithImageSource:aImageSource imageIndex:0];
43 | }
44 |
45 | - (instancetype)initWithImageSource:(id )aImageSource imageIndex:(NSInteger)imageIndex {
46 | if ((self = [super init])) {
47 |
48 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toggleBarsNotification:) name:kFSImageViewerToogleBarsNotificationKey object:nil];
49 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageViewDidFinishLoading:) name:kFSImageViewerDidFinishedLoadingNotificationKey object:nil];
50 |
51 | self.hidesBottomBarWhenPushed = YES;
52 |
53 | self.backgroundColorHidden = [UIColor blackColor];
54 | self.backgroundColorVisible = [UIColor whiteColor];
55 |
56 | self.progressColorHidden = [UIColor whiteColor];
57 | self.progressColorVisible = [UIColor darkGrayColor];
58 |
59 | _imageSource = aImageSource;
60 | pageIndex = imageIndex;
61 | currentPageIndex = imageIndex;
62 |
63 | self.sharingDisabled = NO;
64 | self.showNumberOfItemsInTitle = YES;
65 | self.rotationEnabled = YES;
66 | }
67 | return self;
68 | }
69 |
70 | - (void)dealloc {
71 | _scrollView.delegate = nil;
72 | [[FSImageLoader sharedInstance] cancelAllRequests];
73 | [[NSNotificationCenter defaultCenter] removeObserver:self];
74 | }
75 |
76 | - (void)viewDidLoad {
77 | [super viewDidLoad];
78 |
79 | if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {
80 | self.automaticallyAdjustsScrollViewInsets = NO;
81 | }
82 |
83 | self.view.backgroundColor = self.backgroundColorVisible;
84 |
85 | if (!_scrollView) {
86 | self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
87 | _scrollView.delegate = self;
88 | _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
89 | _scrollView.scrollEnabled = YES;
90 | _scrollView.multipleTouchEnabled = YES;
91 | _scrollView.directionalLockEnabled = YES;
92 | _scrollView.canCancelContentTouches = YES;
93 | _scrollView.delaysContentTouches = YES;
94 | _scrollView.clipsToBounds = YES;
95 | _scrollView.bounces = YES;
96 | _scrollView.alwaysBounceHorizontal = YES;
97 | _scrollView.pagingEnabled = YES;
98 | _scrollView.showsVerticalScrollIndicator = NO;
99 | _scrollView.showsHorizontalScrollIndicator = NO;
100 | _scrollView.backgroundColor = self.view.backgroundColor;
101 | [self.view addSubview:_scrollView];
102 | }
103 |
104 | if (!_titleView) {
105 | [self setTitleView:[[FSImageTitleView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, 1)]];
106 | }
107 |
108 | // load FSImageView lazy
109 | NSMutableArray *views = [[NSMutableArray alloc] init];
110 | for (NSUInteger i = 0; i < [_imageSource numberOfImages]; i++) {
111 | [views addObject:[NSNull null]];
112 | }
113 | self.imageViews = views;
114 | }
115 |
116 | - (void)setTitleView:(UIView *)titleView {
117 | if(_titleView) {
118 | [_titleView removeFromSuperview];
119 | }
120 | _titleView = titleView;
121 | if (_titleView) {
122 | [self.view addSubview:_titleView];
123 | }
124 | }
125 |
126 | - (void)viewWillAppear:(BOOL)animated {
127 | [super viewWillAppear:animated];
128 |
129 | shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(share:)];
130 | shareButton.enabled = NO;
131 | if (self.presentingViewController && (self.modalPresentationStyle == UIModalPresentationFullScreen)) {
132 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:[self localizedStringForKey:@"done" withDefault:@"Done"] style:UIBarButtonItemStyleDone target:self action:@selector(done:)];
133 | self.navigationItem.rightBarButtonItem = doneButton;
134 | if (!_sharingDisabled) {
135 | self.navigationItem.leftBarButtonItem = shareButton;
136 | }
137 | }
138 | else {
139 | if (!_sharingDisabled) {
140 | self.navigationItem.rightBarButtonItem = shareButton;
141 | }
142 | }
143 |
144 | [self setupScrollViewContentSize];
145 | [self moveToImageAtIndex:pageIndex animated:NO];
146 | }
147 |
148 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
149 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
150 | return (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
151 | }
152 |
153 | return (UIInterfaceOrientationIsLandscape(interfaceOrientation) || interfaceOrientation == UIInterfaceOrientationPortrait);
154 | }
155 |
156 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
157 | rotating = YES;
158 |
159 | if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
160 | CGRect rect = [[UIScreen mainScreen] bounds];
161 | _scrollView.contentSize = CGSizeMake(rect.size.height * [_imageSource numberOfImages], rect.size.width);
162 | }
163 |
164 | NSInteger count = 0;
165 | for (FSImageView *view in _imageViews) {
166 | if ([view isKindOfClass:[FSImageView class]]) {
167 | if (count != pageIndex) {
168 | [view setHidden:YES];
169 | }
170 | }
171 | count++;
172 | }
173 | }
174 |
175 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
176 | for (FSImageView *view in _imageViews) {
177 | if ([view isKindOfClass:[FSImageView class]]) {
178 | [view rotateToOrientation:toInterfaceOrientation];
179 | }
180 | }
181 | }
182 |
183 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
184 | [self setupScrollViewContentSize];
185 | [self moveToImageAtIndex:pageIndex animated:NO];
186 | if (pageIndex < [_imageViews count])
187 | [_scrollView scrollRectToVisible:((FSImageView *) [_imageViews objectAtIndex:(NSUInteger) pageIndex]).frame animated:YES];
188 |
189 | for (FSImageView *view in self.imageViews) {
190 | if ([view isKindOfClass:[FSImageView class]]) {
191 | [view setHidden:NO];
192 | }
193 | }
194 | rotating = NO;
195 | }
196 |
197 | - (void)done:(id)sender {
198 | if ([_delegate respondsToSelector:@selector(imageViewerViewController:willDismissViewControllerAnimated:)]) {
199 | [_delegate imageViewerViewController:self willDismissViewControllerAnimated:YES];
200 | }
201 |
202 | [self dismissViewControllerAnimated:YES completion:^{
203 | if ([_delegate respondsToSelector:@selector(imageViewerViewController:didDismissViewControllerAnimated:)]) {
204 | [_delegate imageViewerViewController:self didDismissViewControllerAnimated:YES];
205 | }
206 | }];
207 | }
208 |
209 | - (void)share:(id)sender {
210 | id currentImage = _imageSource[[self currentImageIndex]];
211 | NSAssert(currentImage.image, @"The image must be loaded to share.");
212 | if (currentImage.image) {
213 | UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:@[currentImage.image] applicationActivities:_applicationActivities];
214 | if([controller respondsToSelector:@selector(popoverPresentationController)]) {
215 | if (!controller.popoverPresentationController.barButtonItem) {
216 | controller.popoverPresentationController.barButtonItem = shareButton;
217 | }
218 | }
219 | [self presentViewController:controller animated:YES completion:nil];
220 | }
221 | }
222 |
223 | - (NSInteger)currentImageIndex {
224 | return pageIndex;
225 | }
226 |
227 | #pragma mark - Bar/Caption Methods
228 |
229 | - (void)setStatusBarHidden:(BOOL)hidden {
230 | statusBarHidden = hidden;
231 |
232 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
233 | [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
234 | } else {
235 | [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationFade];
236 | }
237 |
238 | }
239 |
240 | - (void)setBarsHidden:(BOOL)hidden animated:(BOOL)animated {
241 | if (hidden && barsHidden) {
242 | return;
243 | }
244 |
245 | [self setStatusBarHidden:hidden];
246 | [self.navigationController setNavigationBarHidden:hidden animated:animated];
247 |
248 | [UIView animateWithDuration:0.3 animations:^{
249 | UIColor *backgroundColor = hidden ? _backgroundColorHidden : _backgroundColorVisible;
250 | self.view.backgroundColor = backgroundColor;
251 | self.scrollView.backgroundColor = backgroundColor;
252 | for (FSImageView *imageView in _imageViews) {
253 | if ([imageView isKindOfClass:[FSImageView class]]) {
254 | [imageView changeBackgroundColor:backgroundColor];;
255 | [imageView changeProgressViewColor:hidden ? _progressColorHidden : _progressColorVisible];
256 | }
257 | }
258 | }];
259 |
260 | [_titleView hideView:hidden];
261 |
262 | barsHidden = hidden;
263 | }
264 |
265 | - (void)toggleBarsNotification:(NSNotification *)notification {
266 | [self setBarsHidden:!barsHidden animated:YES];
267 | }
268 |
269 | #pragma mark - Image View
270 |
271 | - (void)imageViewDidFinishLoading:(NSNotification *)notification {
272 | if (notification == nil) {
273 | return;
274 | }
275 |
276 | NSInteger centerIndex = [self centerImageIndex];
277 | if (centerIndex >= _imageSource.numberOfImages) {
278 | NSAssert(centerIndex < _imageSource.numberOfImages, @"centerIndex is out of bounds");
279 | return;
280 | }
281 |
282 | if ([[notification object][@"image"] isEqual:_imageSource[centerIndex]]) {
283 | if ([[notification object][@"failed"] boolValue]) {
284 | if (barsHidden) {
285 | [self setBarsHidden:NO animated:YES];
286 | }
287 | shareButton.enabled = NO;
288 | }
289 | else {
290 | shareButton.enabled = YES;
291 | }
292 | [self setViewState];
293 | }
294 | }
295 |
296 | - (NSInteger)centerImageIndex {
297 | if (self.scrollView) {
298 | CGFloat pageWidth = self.scrollView.frame.size.width;
299 | NSInteger centerImageIndex = (NSInteger)(floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1);
300 | if (centerImageIndex >= 0) {
301 | return centerImageIndex;
302 | }
303 | }
304 | return 0;
305 | }
306 |
307 | - (void)setViewState {
308 |
309 | if(_showNumberOfItemsInTitle) {
310 | NSInteger numberOfImages = [_imageSource numberOfImages];
311 | if (numberOfImages > 1) {
312 | self.navigationItem.title = [NSString stringWithFormat:@"%i %@ %li", (int)pageIndex + 1, [self localizedStringForKey:@"imageCounter" withDefault:@"of"], (long)numberOfImages];
313 | } else {
314 | self.title = @"";
315 | }
316 | }
317 |
318 | if (_titleView) {
319 | [_titleView updateMetadata:_imageSource[pageIndex].title index:pageIndex total:_imageSource.numberOfImages];
320 | }
321 |
322 | }
323 |
324 | - (void)moveToImageAtIndex:(NSInteger)index animated:(BOOL)animated {
325 | if (index < [self.imageSource numberOfImages] && index >= 0) {
326 |
327 | BOOL sameIndex = (currentPageIndex == index);
328 | pageIndex = index;
329 | currentPageIndex = index;
330 |
331 | [self setViewState];
332 |
333 | [self enqueueImageViewAtIndex:index];
334 |
335 | [self loadScrollViewWithPage:index - 1];
336 | [self loadScrollViewWithPage:index];
337 | [self loadScrollViewWithPage:index + 1];
338 |
339 | [self.scrollView scrollRectToVisible:((FSImageView *) [_imageViews objectAtIndex:(NSUInteger) index]).frame animated:animated];
340 |
341 | if (_imageSource[pageIndex].failed) {
342 | [self setBarsHidden:NO animated:YES];
343 | shareButton.enabled = NO;
344 | }
345 | else {
346 | if (pageIndex == [self currentImageIndex] && _imageSource[pageIndex].image) {
347 | shareButton.enabled = YES;
348 | if (!sameIndex && [_delegate respondsToSelector:@selector(imageViewerViewController:didMoveToImageAtIndex:)]) {
349 | [_delegate imageViewerViewController:self didMoveToImageAtIndex:pageIndex];
350 | }
351 | }
352 | }
353 |
354 | if (index + 1 < [self.imageSource numberOfImages] && (NSNull *) [_imageViews objectAtIndex:(NSUInteger) (index + 1)] != [NSNull null]) {
355 | [((FSImageView *) [self.imageViews objectAtIndex:(NSUInteger) (index + 1)]) killScrollViewZoom];
356 | }
357 | if (index - 1 >= 0 && (NSNull *) [self.imageViews objectAtIndex:(NSUInteger) (index - 1)] != [NSNull null]) {
358 | [((FSImageView *) [self.imageViews objectAtIndex:(NSUInteger) (index - 1)]) killScrollViewZoom];
359 | }
360 | }
361 |
362 | }
363 |
364 | - (void)layoutScrollViewSubviews {
365 |
366 | NSInteger index = [self currentImageIndex];
367 |
368 | for (NSInteger page = index - 1; page < index + 3; page++) {
369 |
370 | if (page >= 0 && page < [_imageSource numberOfImages]) {
371 |
372 | CGFloat originX = _scrollView.bounds.size.width * page;
373 |
374 | if (page < index) {
375 | originX -= kFSImageViewerImageGap;
376 | }
377 | if (page > index) {
378 | originX += kFSImageViewerImageGap;
379 | }
380 |
381 | if ([_imageViews objectAtIndex:(NSUInteger) page] == [NSNull null] || !((UIView *) [_imageViews objectAtIndex:(NSUInteger) page]).superview) {
382 | [self loadScrollViewWithPage:page];
383 | }
384 |
385 | FSImageView *imageView = [_imageViews objectAtIndex:(NSUInteger) page];
386 | CGRect newFrame = CGRectMake(originX, 0.0f, _scrollView.bounds.size.width, _scrollView.bounds.size.height);
387 |
388 | if (!CGRectEqualToRect(imageView.frame, newFrame)) {
389 | [UIView animateWithDuration:0.1 animations:^{
390 | imageView.frame = newFrame;
391 | }];
392 | }
393 | }
394 | }
395 | }
396 |
397 | - (void)setupScrollViewContentSize {
398 |
399 | CGSize contentSize = self.view.bounds.size;
400 | contentSize.width = (contentSize.width * [_imageSource numberOfImages]);
401 |
402 | if (!CGSizeEqualToSize(contentSize, self.scrollView.contentSize)) {
403 | self.scrollView.contentSize = contentSize;
404 | }
405 |
406 | if (![_titleView isHidden]) {
407 | [_titleView adjustTextViewSize:self.view.bounds];
408 | }
409 | }
410 |
411 | - (void)enqueueImageViewAtIndex:(NSInteger)theIndex {
412 |
413 | NSInteger count = 0;
414 | for (FSImageView *view in _imageViews) {
415 | if ([view isKindOfClass:[FSImageView class]]) {
416 | if (count > theIndex + 1 || count < theIndex - 1) {
417 | [view prepareForReuse];
418 | [view removeFromSuperview];
419 | } else {
420 | view.tag = 0;
421 | }
422 | }
423 | count++;
424 | }
425 | }
426 |
427 | - (FSImageView *)dequeueImageView {
428 |
429 | NSInteger count = 0;
430 | for (FSImageView *view in self.imageViews) {
431 | if ([view isKindOfClass:[FSImageView class]]) {
432 | if (view.superview == nil) {
433 | view.tag = count;
434 | return view;
435 | }
436 | }
437 | count++;
438 | }
439 | return nil;
440 | }
441 |
442 | - (void)loadScrollViewWithPage:(NSInteger)page {
443 |
444 | if (page < 0) {
445 | return;
446 | }
447 | if (page >= [_imageSource numberOfImages]) {
448 | return;
449 | }
450 |
451 | FSImageView *imageView = [_imageViews objectAtIndex:(NSUInteger) page];
452 | if ((NSNull *) imageView == [NSNull null]) {
453 | imageView = [self dequeueImageView];
454 | if (imageView != nil) {
455 | [_imageViews exchangeObjectAtIndex:(NSUInteger) imageView.tag withObjectAtIndex:(NSUInteger) page];
456 | imageView = [_imageViews objectAtIndex:(NSUInteger) page];
457 | }
458 | }
459 |
460 | if (imageView == nil || (NSNull *) imageView == [NSNull null]) {
461 | imageView = [[FSImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _scrollView.bounds.size.width, _scrollView.bounds.size.height)];
462 | imageView.rotationEnabled = _rotationEnabled;
463 | UIColor *backgroundColor = barsHidden ? _backgroundColorHidden : _backgroundColorVisible;
464 | [imageView changeBackgroundColor:backgroundColor];
465 | [imageView changeProgressViewColor:barsHidden ? _progressColorHidden : _progressColorVisible];
466 | [_imageViews replaceObjectAtIndex:(NSUInteger) page withObject:imageView];
467 | }
468 |
469 | imageView.image = _imageSource[page];
470 |
471 | if (imageView.superview == nil) {
472 | [_scrollView addSubview:imageView];
473 | }
474 |
475 | CGRect frame = _scrollView.frame;
476 | NSInteger centerPageIndex = pageIndex;
477 | CGFloat xOrigin = (frame.size.width * page);
478 | if (page > centerPageIndex) {
479 | xOrigin = (frame.size.width * page) + kFSImageViewerImageGap;
480 | } else if (page < centerPageIndex) {
481 | xOrigin = (frame.size.width * page) - kFSImageViewerImageGap;
482 | }
483 |
484 | frame.origin.x = xOrigin;
485 | frame.origin.y = 0;
486 | imageView.frame = frame;
487 | }
488 |
489 | #pragma mark - UIScrollViewDelegate
490 |
491 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
492 | NSInteger index = [self centerImageIndex];
493 | if (index >= [_imageSource numberOfImages] || index < 0) {
494 | return;
495 | }
496 |
497 | if (pageIndex != index && !rotating) {
498 | pageIndex = index;
499 | [self setViewState];
500 |
501 | if (![scrollView isTracking]) {
502 | [self layoutScrollViewSubviews];
503 | }
504 | }
505 | }
506 |
507 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
508 | NSInteger index = [self centerImageIndex];
509 | if (index >= [_imageSource numberOfImages] || index < 0) {
510 | return;
511 | }
512 |
513 | [self moveToImageAtIndex:index animated:YES];
514 | }
515 |
516 | - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
517 | [self layoutScrollViewSubviews];
518 | }
519 |
520 | - (BOOL)prefersStatusBarHidden {
521 | return statusBarHidden;
522 | }
523 |
524 | #pragma mark - Localization Helper
525 | - (NSString *)localizedStringForKey:(NSString *)key withDefault:(NSString *)defaultString
526 | {
527 | static NSBundle *bundle = nil;
528 | if (bundle == nil)
529 | {
530 | NSString *bundlePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"FSImageViewer" ofType:@"bundle"];
531 | bundle = [NSBundle bundleWithPath:bundlePath] ?: [NSBundle bundleForClass:[self class]];
532 | for (NSString *language in [NSLocale preferredLanguages])
533 | {
534 | if ([[bundle localizations] containsObject:language])
535 | {
536 | bundlePath = [bundle pathForResource:language ofType:@"lproj"];
537 | bundle = [NSBundle bundleWithPath:bundlePath];
538 | break;
539 | }
540 | }
541 | }
542 | defaultString = [bundle localizedStringForKey:key value:defaultString table:nil];
543 | return [[NSBundle bundleForClass:[self class]] localizedStringForKey:key value:defaultString table:nil];
544 | }
545 |
546 | @end
547 |
--------------------------------------------------------------------------------
/FSImageViewer.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 53EF70271A9A38B9000FBFE2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53EF70261A9A38B9000FBFE2 /* Images.xcassets */; };
11 | 5AB0DA258592480FB4099411 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 746D153768E9481F8194ECCE /* libPods.a */; };
12 | 69855A85F6C241808F6F609F /* libPods-FSImageViewerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E4F4DB52EA04D489651AD23 /* libPods-FSImageViewerTests.a */; };
13 | FD0FEFBB17D77F1C00470082 /* FSBasicImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = FD0FEFBA17D77F1C00470082 /* FSBasicImageSource.m */; };
14 | FD0FEFBF17D781EF00470082 /* FSBasicImage.m in Sources */ = {isa = PBXBuildFile; fileRef = FD0FEFBE17D781EF00470082 /* FSBasicImage.m */; };
15 | FD37CEC0181EBA5700606D81 /* FSImageViewer.bundle in Resources */ = {isa = PBXBuildFile; fileRef = FD37CEBF181EBA5700606D81 /* FSImageViewer.bundle */; };
16 | FD89E29417CB99D900A41D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E29317CB99D900A41D91 /* Foundation.framework */; };
17 | FD89E2A717CB99F000A41D91 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E2A617CB99F000A41D91 /* UIKit.framework */; };
18 | FD89E2A817CB99F000A41D91 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E29317CB99D900A41D91 /* Foundation.framework */; };
19 | FD89E2AA17CB99F000A41D91 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E2A917CB99F000A41D91 /* CoreGraphics.framework */; };
20 | FD89E2B017CB99F000A41D91 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FD89E2AE17CB99F000A41D91 /* InfoPlist.strings */; };
21 | FD89E2B217CB99F000A41D91 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2B117CB99F000A41D91 /* main.m */; };
22 | FD89E2B617CB99F000A41D91 /* FSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2B517CB99F000A41D91 /* FSAppDelegate.m */; };
23 | FD89E2CA17CB9A0700A41D91 /* FSImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2C217CB9A0700A41D91 /* FSImageLoader.m */; };
24 | FD89E2CB17CB9A0700A41D91 /* FSImageScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2C417CB9A0700A41D91 /* FSImageScrollView.m */; };
25 | FD89E2CC17CB9A0700A41D91 /* FSImageTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2C717CB9A0700A41D91 /* FSImageTitleView.m */; };
26 | FD89E2CD17CB9A0700A41D91 /* FSImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2C917CB9A0700A41D91 /* FSImageView.m */; };
27 | FD89E2D217CB9A0E00A41D91 /* FSImageViewerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2CF17CB9A0E00A41D91 /* FSImageViewerViewController.m */; };
28 | FD89E2D317CB9A0E00A41D91 /* FSPlaceholderImages.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2D117CB9A0E00A41D91 /* FSPlaceholderImages.m */; };
29 | FD89E2DD17CB9A4400A41D91 /* FSDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD89E2D917CB9A4400A41D91 /* FSDemoViewController.m */; };
30 | FD89E2DE17CB9A4400A41D91 /* FSDemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FD89E2DA17CB9A4400A41D91 /* FSDemoViewController.xib */; };
31 | FD8B868C1BAD6F2400EA0D5D /* FSImageViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD8B868B1BAD6F2400EA0D5D /* FSImageViewTests.m */; settings = {ASSET_TAGS = (); }; };
32 | FD8B868E1BAD97DC00EA0D5D /* Testimage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = FD8B868D1BAD97DC00EA0D5D /* Testimage.jpg */; settings = {ASSET_TAGS = (); }; };
33 | FD8B86921BAD986B00EA0D5D /* FSTestImageHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = FD8B86911BAD986B00EA0D5D /* FSTestImageHelper.m */; settings = {ASSET_TAGS = (); }; };
34 | FD8B86941BAD9C0B00EA0D5D /* FSBasicImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD8B86931BAD9C0B00EA0D5D /* FSBasicImageSourceTests.m */; settings = {ASSET_TAGS = (); }; };
35 | FDBD6630193B054F006D3BF6 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDBD662F193B054F006D3BF6 /* XCTest.framework */; };
36 | FDBD6631193B054F006D3BF6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E29317CB99D900A41D91 /* Foundation.framework */; };
37 | FDBD6632193B054F006D3BF6 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E2A617CB99F000A41D91 /* UIKit.framework */; };
38 | FDBD6638193B054F006D3BF6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FDBD6636193B054F006D3BF6 /* InfoPlist.strings */; };
39 | FDBD663A193B054F006D3BF6 /* FSImageTitleViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FDBD6639193B054F006D3BF6 /* FSImageTitleViewTests.m */; };
40 | FDCB0B27193B956500F8B8A1 /* FSPlaceholderImagesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FDCB0B26193B956500F8B8A1 /* FSPlaceholderImagesTests.m */; };
41 | FDD96CE417CB9B7400B66931 /* libFSImageViewer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD89E29017CB99D900A41D91 /* libFSImageViewer.a */; };
42 | FDD96CEB17CB9B9000B66931 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDD96CE917CB9B8800B66931 /* CFNetwork.framework */; };
43 | FDD96CEC17CB9B9100B66931 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDD96CE717CB9B8500B66931 /* Security.framework */; };
44 | FDD96CED17CB9B9300B66931 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDD96CE517CB9B8000B66931 /* QuartzCore.framework */; };
45 | /* End PBXBuildFile section */
46 |
47 | /* Begin PBXContainerItemProxy section */
48 | FDBD663C193B054F006D3BF6 /* PBXContainerItemProxy */ = {
49 | isa = PBXContainerItemProxy;
50 | containerPortal = FD89E28817CB99D900A41D91 /* Project object */;
51 | proxyType = 1;
52 | remoteGlobalIDString = FD89E28F17CB99D900A41D91;
53 | remoteInfo = FSImageViewer;
54 | };
55 | FDD96CE217CB9B7000B66931 /* PBXContainerItemProxy */ = {
56 | isa = PBXContainerItemProxy;
57 | containerPortal = FD89E28817CB99D900A41D91 /* Project object */;
58 | proxyType = 1;
59 | remoteGlobalIDString = FD89E28F17CB99D900A41D91;
60 | remoteInfo = FSImageViewer;
61 | };
62 | FDF817081BAC2C75001337B4 /* PBXContainerItemProxy */ = {
63 | isa = PBXContainerItemProxy;
64 | containerPortal = FD89E28817CB99D900A41D91 /* Project object */;
65 | proxyType = 1;
66 | remoteGlobalIDString = FD89E2A417CB99F000A41D91;
67 | remoteInfo = FSImageViewerDemo;
68 | };
69 | /* End PBXContainerItemProxy section */
70 |
71 | /* Begin PBXCopyFilesBuildPhase section */
72 | FD89E28E17CB99D900A41D91 /* CopyFiles */ = {
73 | isa = PBXCopyFilesBuildPhase;
74 | buildActionMask = 2147483647;
75 | dstPath = "include/${PRODUCT_NAME}";
76 | dstSubfolderSpec = 16;
77 | files = (
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | /* End PBXCopyFilesBuildPhase section */
82 |
83 | /* Begin PBXFileReference section */
84 | 2926F8C4CE2E738802DA8060 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; };
85 | 3E4F4DB52EA04D489651AD23 /* libPods-FSImageViewerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FSImageViewerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
86 | 53EF70261A9A38B9000FBFE2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
87 | 589F82D818EDE791007F654A /* FSTitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTitleView.h; sourceTree = ""; };
88 | 746D153768E9481F8194ECCE /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
89 | 85A9CBC49B63FEB31F1448F5 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; };
90 | EAB987CD32B1D53A7F4A3B72 /* Pods-FSImageViewerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FSImageViewerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FSImageViewerTests/Pods-FSImageViewerTests.release.xcconfig"; sourceTree = ""; };
91 | F438121ACBFC9888194F99FE /* Pods-FSImageViewerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FSImageViewerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FSImageViewerTests/Pods-FSImageViewerTests.debug.xcconfig"; sourceTree = ""; };
92 | FD0FEFB917D77F1C00470082 /* FSBasicImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSBasicImageSource.h; sourceTree = ""; };
93 | FD0FEFBA17D77F1C00470082 /* FSBasicImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSBasicImageSource.m; sourceTree = ""; };
94 | FD0FEFBD17D781EF00470082 /* FSBasicImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSBasicImage.h; sourceTree = ""; };
95 | FD0FEFBE17D781EF00470082 /* FSBasicImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSBasicImage.m; sourceTree = ""; };
96 | FD37CEBF181EBA5700606D81 /* FSImageViewer.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FSImageViewer.bundle; sourceTree = SOURCE_ROOT; };
97 | FD37CEC1181EBCDC00606D81 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; };
98 | FD37CEC2181EBCE000606D81 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; };
99 | FD37CEC3181EBCEC00606D81 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; };
100 | FD37CEC4181EBCF400606D81 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; };
101 | FD37CEC5181EC01700606D81 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; };
102 | FD37CEC6181EC01E00606D81 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; };
103 | FD89E29017CB99D900A41D91 /* libFSImageViewer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFSImageViewer.a; sourceTree = BUILT_PRODUCTS_DIR; };
104 | FD89E29317CB99D900A41D91 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
105 | FD89E29717CB99D900A41D91 /* FSImageViewer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSImageViewer-Prefix.pch"; sourceTree = ""; };
106 | FD89E2A517CB99F000A41D91 /* FSImageViewerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FSImageViewerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
107 | FD89E2A617CB99F000A41D91 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
108 | FD89E2A917CB99F000A41D91 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
109 | FD89E2AD17CB99F000A41D91 /* FSImageViewerDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FSImageViewerDemo-Info.plist"; sourceTree = ""; };
110 | FD89E2AF17CB99F000A41D91 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
111 | FD89E2B117CB99F000A41D91 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
112 | FD89E2B317CB99F000A41D91 /* FSImageViewerDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSImageViewerDemo-Prefix.pch"; sourceTree = ""; };
113 | FD89E2B417CB99F000A41D91 /* FSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FSAppDelegate.h; sourceTree = ""; };
114 | FD89E2B517CB99F000A41D91 /* FSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSAppDelegate.m; sourceTree = ""; };
115 | FD89E2C017CB9A0700A41D91 /* FSImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImage.h; sourceTree = ""; };
116 | FD89E2C117CB9A0700A41D91 /* FSImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageLoader.h; sourceTree = ""; };
117 | FD89E2C217CB9A0700A41D91 /* FSImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageLoader.m; sourceTree = ""; };
118 | FD89E2C317CB9A0700A41D91 /* FSImageScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageScrollView.h; sourceTree = ""; };
119 | FD89E2C417CB9A0700A41D91 /* FSImageScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageScrollView.m; sourceTree = ""; };
120 | FD89E2C517CB9A0700A41D91 /* FSImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageSource.h; sourceTree = ""; };
121 | FD89E2C617CB9A0700A41D91 /* FSImageTitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageTitleView.h; sourceTree = ""; };
122 | FD89E2C717CB9A0700A41D91 /* FSImageTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageTitleView.m; sourceTree = ""; };
123 | FD89E2C817CB9A0700A41D91 /* FSImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageView.h; sourceTree = ""; };
124 | FD89E2C917CB9A0700A41D91 /* FSImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageView.m; sourceTree = ""; };
125 | FD89E2CE17CB9A0E00A41D91 /* FSImageViewerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageViewerViewController.h; sourceTree = ""; };
126 | FD89E2CF17CB9A0E00A41D91 /* FSImageViewerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageViewerViewController.m; sourceTree = ""; };
127 | FD89E2D017CB9A0E00A41D91 /* FSPlaceholderImages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSPlaceholderImages.h; sourceTree = ""; };
128 | FD89E2D117CB9A0E00A41D91 /* FSPlaceholderImages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSPlaceholderImages.m; sourceTree = ""; };
129 | FD89E2D817CB9A4400A41D91 /* FSDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSDemoViewController.h; sourceTree = ""; };
130 | FD89E2D917CB9A4400A41D91 /* FSDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSDemoViewController.m; sourceTree = ""; };
131 | FD89E2DA17CB9A4400A41D91 /* FSDemoViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FSDemoViewController.xib; sourceTree = ""; };
132 | FD8B868B1BAD6F2400EA0D5D /* FSImageViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSImageViewTests.m; sourceTree = ""; };
133 | FD8B868D1BAD97DC00EA0D5D /* Testimage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Testimage.jpg; sourceTree = ""; };
134 | FD8B86901BAD986B00EA0D5D /* FSTestImageHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTestImageHelper.h; sourceTree = ""; };
135 | FD8B86911BAD986B00EA0D5D /* FSTestImageHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTestImageHelper.m; sourceTree = ""; };
136 | FD8B86931BAD9C0B00EA0D5D /* FSBasicImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSBasicImageSourceTests.m; sourceTree = ""; };
137 | FDBD662E193B054F006D3BF6 /* FSImageViewerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FSImageViewerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
138 | FDBD662F193B054F006D3BF6 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
139 | FDBD6635193B054F006D3BF6 /* FSImageViewerTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FSImageViewerTests-Info.plist"; sourceTree = ""; };
140 | FDBD6637193B054F006D3BF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
141 | FDBD6639193B054F006D3BF6 /* FSImageTitleViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSImageTitleViewTests.m; sourceTree = ""; };
142 | FDBD663B193B054F006D3BF6 /* FSImageViewerTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSImageViewerTests-Prefix.pch"; sourceTree = ""; };
143 | FDCB0B26193B956500F8B8A1 /* FSPlaceholderImagesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSPlaceholderImagesTests.m; sourceTree = ""; };
144 | FDD96CE117CB9ADC00B66931 /* FSImageViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSImageViewer.h; sourceTree = ""; };
145 | FDD96CE517CB9B8000B66931 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
146 | FDD96CE717CB9B8500B66931 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
147 | FDD96CE917CB9B8800B66931 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
148 | /* End PBXFileReference section */
149 |
150 | /* Begin PBXFrameworksBuildPhase section */
151 | FD89E28D17CB99D900A41D91 /* Frameworks */ = {
152 | isa = PBXFrameworksBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | FD89E29417CB99D900A41D91 /* Foundation.framework in Frameworks */,
156 | 5AB0DA258592480FB4099411 /* libPods.a in Frameworks */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | FD89E2A217CB99F000A41D91 /* Frameworks */ = {
161 | isa = PBXFrameworksBuildPhase;
162 | buildActionMask = 2147483647;
163 | files = (
164 | FDD96CE417CB9B7400B66931 /* libFSImageViewer.a in Frameworks */,
165 | FDD96CEB17CB9B9000B66931 /* CFNetwork.framework in Frameworks */,
166 | FDD96CEC17CB9B9100B66931 /* Security.framework in Frameworks */,
167 | FDD96CED17CB9B9300B66931 /* QuartzCore.framework in Frameworks */,
168 | FD89E2A717CB99F000A41D91 /* UIKit.framework in Frameworks */,
169 | FD89E2A817CB99F000A41D91 /* Foundation.framework in Frameworks */,
170 | FD89E2AA17CB99F000A41D91 /* CoreGraphics.framework in Frameworks */,
171 | );
172 | runOnlyForDeploymentPostprocessing = 0;
173 | };
174 | FDBD662B193B054F006D3BF6 /* Frameworks */ = {
175 | isa = PBXFrameworksBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | FDBD6630193B054F006D3BF6 /* XCTest.framework in Frameworks */,
179 | FDBD6632193B054F006D3BF6 /* UIKit.framework in Frameworks */,
180 | FDBD6631193B054F006D3BF6 /* Foundation.framework in Frameworks */,
181 | 69855A85F6C241808F6F609F /* libPods-FSImageViewerTests.a in Frameworks */,
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | };
185 | /* End PBXFrameworksBuildPhase section */
186 |
187 | /* Begin PBXGroup section */
188 | 09EB87C7BA5D8A556339C8D3 /* Pods */ = {
189 | isa = PBXGroup;
190 | children = (
191 | 85A9CBC49B63FEB31F1448F5 /* Pods.debug.xcconfig */,
192 | 2926F8C4CE2E738802DA8060 /* Pods.release.xcconfig */,
193 | F438121ACBFC9888194F99FE /* Pods-FSImageViewerTests.debug.xcconfig */,
194 | EAB987CD32B1D53A7F4A3B72 /* Pods-FSImageViewerTests.release.xcconfig */,
195 | );
196 | name = Pods;
197 | sourceTree = "";
198 | };
199 | FD89E28717CB99D900A41D91 = {
200 | isa = PBXGroup;
201 | children = (
202 | FD89E29517CB99D900A41D91 /* FSImageViewer */,
203 | FD89E2AB17CB99F000A41D91 /* FSImageViewerDemo */,
204 | FDBD6633193B054F006D3BF6 /* FSImageViewerTests */,
205 | FD89E29217CB99D900A41D91 /* Frameworks */,
206 | FD89E29117CB99D900A41D91 /* Products */,
207 | 09EB87C7BA5D8A556339C8D3 /* Pods */,
208 | );
209 | sourceTree = "";
210 | };
211 | FD89E29117CB99D900A41D91 /* Products */ = {
212 | isa = PBXGroup;
213 | children = (
214 | FD89E29017CB99D900A41D91 /* libFSImageViewer.a */,
215 | FD89E2A517CB99F000A41D91 /* FSImageViewerDemo.app */,
216 | FDBD662E193B054F006D3BF6 /* FSImageViewerTests.xctest */,
217 | );
218 | name = Products;
219 | sourceTree = "";
220 | };
221 | FD89E29217CB99D900A41D91 /* Frameworks */ = {
222 | isa = PBXGroup;
223 | children = (
224 | FDD96CE917CB9B8800B66931 /* CFNetwork.framework */,
225 | FDD96CE717CB9B8500B66931 /* Security.framework */,
226 | FDD96CE517CB9B8000B66931 /* QuartzCore.framework */,
227 | FD89E29317CB99D900A41D91 /* Foundation.framework */,
228 | FD89E2A617CB99F000A41D91 /* UIKit.framework */,
229 | FD89E2A917CB99F000A41D91 /* CoreGraphics.framework */,
230 | 746D153768E9481F8194ECCE /* libPods.a */,
231 | FDBD662F193B054F006D3BF6 /* XCTest.framework */,
232 | 3E4F4DB52EA04D489651AD23 /* libPods-FSImageViewerTests.a */,
233 | );
234 | name = Frameworks;
235 | sourceTree = "";
236 | };
237 | FD89E29517CB99D900A41D91 /* FSImageViewer */ = {
238 | isa = PBXGroup;
239 | children = (
240 | FD0FEFBD17D781EF00470082 /* FSBasicImage.h */,
241 | FD0FEFBE17D781EF00470082 /* FSBasicImage.m */,
242 | FD0FEFB917D77F1C00470082 /* FSBasicImageSource.h */,
243 | FD0FEFBA17D77F1C00470082 /* FSBasicImageSource.m */,
244 | FD89E2C017CB9A0700A41D91 /* FSImage.h */,
245 | FD89E2C117CB9A0700A41D91 /* FSImageLoader.h */,
246 | FD89E2C217CB9A0700A41D91 /* FSImageLoader.m */,
247 | FD89E2C317CB9A0700A41D91 /* FSImageScrollView.h */,
248 | FD89E2C417CB9A0700A41D91 /* FSImageScrollView.m */,
249 | FD89E2C517CB9A0700A41D91 /* FSImageSource.h */,
250 | FD89E2C617CB9A0700A41D91 /* FSImageTitleView.h */,
251 | FD89E2C717CB9A0700A41D91 /* FSImageTitleView.m */,
252 | FD89E2C817CB9A0700A41D91 /* FSImageView.h */,
253 | FD89E2C917CB9A0700A41D91 /* FSImageView.m */,
254 | FD37CEBF181EBA5700606D81 /* FSImageViewer.bundle */,
255 | FDD96CE117CB9ADC00B66931 /* FSImageViewer.h */,
256 | FD89E2CE17CB9A0E00A41D91 /* FSImageViewerViewController.h */,
257 | FD89E2CF17CB9A0E00A41D91 /* FSImageViewerViewController.m */,
258 | FD89E2D017CB9A0E00A41D91 /* FSPlaceholderImages.h */,
259 | FD89E2D117CB9A0E00A41D91 /* FSPlaceholderImages.m */,
260 | 589F82D818EDE791007F654A /* FSTitleView.h */,
261 | FD89E29617CB99D900A41D91 /* Supporting Files */,
262 | );
263 | path = FSImageViewer;
264 | sourceTree = "";
265 | };
266 | FD89E29617CB99D900A41D91 /* Supporting Files */ = {
267 | isa = PBXGroup;
268 | children = (
269 | FD89E29717CB99D900A41D91 /* FSImageViewer-Prefix.pch */,
270 | );
271 | name = "Supporting Files";
272 | sourceTree = "";
273 | };
274 | FD89E2AB17CB99F000A41D91 /* FSImageViewerDemo */ = {
275 | isa = PBXGroup;
276 | children = (
277 | FD89E2B417CB99F000A41D91 /* FSAppDelegate.h */,
278 | FD89E2B517CB99F000A41D91 /* FSAppDelegate.m */,
279 | FD89E2D817CB9A4400A41D91 /* FSDemoViewController.h */,
280 | FD89E2D917CB9A4400A41D91 /* FSDemoViewController.m */,
281 | FD89E2DA17CB9A4400A41D91 /* FSDemoViewController.xib */,
282 | 53EF70261A9A38B9000FBFE2 /* Images.xcassets */,
283 | FD89E2AC17CB99F000A41D91 /* Supporting Files */,
284 | );
285 | path = FSImageViewerDemo;
286 | sourceTree = "";
287 | };
288 | FD89E2AC17CB99F000A41D91 /* Supporting Files */ = {
289 | isa = PBXGroup;
290 | children = (
291 | FD89E2AD17CB99F000A41D91 /* FSImageViewerDemo-Info.plist */,
292 | FD89E2AE17CB99F000A41D91 /* InfoPlist.strings */,
293 | FD89E2B117CB99F000A41D91 /* main.m */,
294 | FD89E2B317CB99F000A41D91 /* FSImageViewerDemo-Prefix.pch */,
295 | );
296 | name = "Supporting Files";
297 | sourceTree = "";
298 | };
299 | FD8B868F1BAD985600EA0D5D /* Helper */ = {
300 | isa = PBXGroup;
301 | children = (
302 | FD8B86901BAD986B00EA0D5D /* FSTestImageHelper.h */,
303 | FD8B86911BAD986B00EA0D5D /* FSTestImageHelper.m */,
304 | );
305 | name = Helper;
306 | sourceTree = "";
307 | };
308 | FDBD6633193B054F006D3BF6 /* FSImageViewerTests */ = {
309 | isa = PBXGroup;
310 | children = (
311 | FD8B868F1BAD985600EA0D5D /* Helper */,
312 | FD8B86931BAD9C0B00EA0D5D /* FSBasicImageSourceTests.m */,
313 | FDBD6639193B054F006D3BF6 /* FSImageTitleViewTests.m */,
314 | FDCB0B26193B956500F8B8A1 /* FSPlaceholderImagesTests.m */,
315 | FD8B868B1BAD6F2400EA0D5D /* FSImageViewTests.m */,
316 | FD8B868D1BAD97DC00EA0D5D /* Testimage.jpg */,
317 | FDBD6634193B054F006D3BF6 /* Supporting Files */,
318 | );
319 | path = FSImageViewerTests;
320 | sourceTree = "";
321 | };
322 | FDBD6634193B054F006D3BF6 /* Supporting Files */ = {
323 | isa = PBXGroup;
324 | children = (
325 | FDBD6635193B054F006D3BF6 /* FSImageViewerTests-Info.plist */,
326 | FDBD6636193B054F006D3BF6 /* InfoPlist.strings */,
327 | FDBD663B193B054F006D3BF6 /* FSImageViewerTests-Prefix.pch */,
328 | );
329 | name = "Supporting Files";
330 | sourceTree = "";
331 | };
332 | /* End PBXGroup section */
333 |
334 | /* Begin PBXNativeTarget section */
335 | FD89E28F17CB99D900A41D91 /* FSImageViewer */ = {
336 | isa = PBXNativeTarget;
337 | buildConfigurationList = FD89E29E17CB99D900A41D91 /* Build configuration list for PBXNativeTarget "FSImageViewer" */;
338 | buildPhases = (
339 | 668C822E290F479BBF42B716 /* Check Pods Manifest.lock */,
340 | FD89E28C17CB99D900A41D91 /* Sources */,
341 | FD89E28D17CB99D900A41D91 /* Frameworks */,
342 | FD89E28E17CB99D900A41D91 /* CopyFiles */,
343 | F7A857B1B6AA493B8B48C1BD /* Copy Pods Resources */,
344 | );
345 | buildRules = (
346 | );
347 | dependencies = (
348 | );
349 | name = FSImageViewer;
350 | productName = FSImageViewer;
351 | productReference = FD89E29017CB99D900A41D91 /* libFSImageViewer.a */;
352 | productType = "com.apple.product-type.library.static";
353 | };
354 | FD89E2A417CB99F000A41D91 /* FSImageViewerDemo */ = {
355 | isa = PBXNativeTarget;
356 | buildConfigurationList = FD89E2BD17CB99F000A41D91 /* Build configuration list for PBXNativeTarget "FSImageViewerDemo" */;
357 | buildPhases = (
358 | 22672DA7B2433B000CF2AAD2 /* Check Pods Manifest.lock */,
359 | FD89E2A117CB99F000A41D91 /* Sources */,
360 | FD89E2A217CB99F000A41D91 /* Frameworks */,
361 | FD89E2A317CB99F000A41D91 /* Resources */,
362 | 70F9CA2574253E876D355FA3 /* Copy Pods Resources */,
363 | );
364 | buildRules = (
365 | );
366 | dependencies = (
367 | FDD96CE317CB9B7000B66931 /* PBXTargetDependency */,
368 | );
369 | name = FSImageViewerDemo;
370 | productName = FSImageViewerDemo;
371 | productReference = FD89E2A517CB99F000A41D91 /* FSImageViewerDemo.app */;
372 | productType = "com.apple.product-type.application";
373 | };
374 | FDBD662D193B054F006D3BF6 /* FSImageViewerTests */ = {
375 | isa = PBXNativeTarget;
376 | buildConfigurationList = FDBD6640193B054F006D3BF6 /* Build configuration list for PBXNativeTarget "FSImageViewerTests" */;
377 | buildPhases = (
378 | E172C5EA369C4663AD247B30 /* Check Pods Manifest.lock */,
379 | FDBD662A193B054F006D3BF6 /* Sources */,
380 | FDBD662B193B054F006D3BF6 /* Frameworks */,
381 | FDBD662C193B054F006D3BF6 /* Resources */,
382 | E9DCDA9D0E3F44EB95291CBC /* Copy Pods Resources */,
383 | );
384 | buildRules = (
385 | );
386 | dependencies = (
387 | FDBD663D193B054F006D3BF6 /* PBXTargetDependency */,
388 | FDF817091BAC2C75001337B4 /* PBXTargetDependency */,
389 | );
390 | name = FSImageViewerTests;
391 | productName = FSImageViewerTests;
392 | productReference = FDBD662E193B054F006D3BF6 /* FSImageViewerTests.xctest */;
393 | productType = "com.apple.product-type.bundle.unit-test";
394 | };
395 | /* End PBXNativeTarget section */
396 |
397 | /* Begin PBXProject section */
398 | FD89E28817CB99D900A41D91 /* Project object */ = {
399 | isa = PBXProject;
400 | attributes = {
401 | LastUpgradeCheck = 0700;
402 | ORGANIZATIONNAME = "Felix Schulze";
403 | TargetAttributes = {
404 | FDBD662D193B054F006D3BF6 = {
405 | TestTargetID = FD89E2A417CB99F000A41D91;
406 | };
407 | };
408 | };
409 | buildConfigurationList = FD89E28B17CB99D900A41D91 /* Build configuration list for PBXProject "FSImageViewer" */;
410 | compatibilityVersion = "Xcode 3.2";
411 | developmentRegion = English;
412 | hasScannedForEncodings = 0;
413 | knownRegions = (
414 | en,
415 | de,
416 | it,
417 | es,
418 | fr,
419 | nl,
420 | ru,
421 | );
422 | mainGroup = FD89E28717CB99D900A41D91;
423 | productRefGroup = FD89E29117CB99D900A41D91 /* Products */;
424 | projectDirPath = "";
425 | projectRoot = "";
426 | targets = (
427 | FD89E28F17CB99D900A41D91 /* FSImageViewer */,
428 | FD89E2A417CB99F000A41D91 /* FSImageViewerDemo */,
429 | FDBD662D193B054F006D3BF6 /* FSImageViewerTests */,
430 | );
431 | };
432 | /* End PBXProject section */
433 |
434 | /* Begin PBXResourcesBuildPhase section */
435 | FD89E2A317CB99F000A41D91 /* Resources */ = {
436 | isa = PBXResourcesBuildPhase;
437 | buildActionMask = 2147483647;
438 | files = (
439 | FD89E2B017CB99F000A41D91 /* InfoPlist.strings in Resources */,
440 | 53EF70271A9A38B9000FBFE2 /* Images.xcassets in Resources */,
441 | FD37CEC0181EBA5700606D81 /* FSImageViewer.bundle in Resources */,
442 | FD89E2DE17CB9A4400A41D91 /* FSDemoViewController.xib in Resources */,
443 | );
444 | runOnlyForDeploymentPostprocessing = 0;
445 | };
446 | FDBD662C193B054F006D3BF6 /* Resources */ = {
447 | isa = PBXResourcesBuildPhase;
448 | buildActionMask = 2147483647;
449 | files = (
450 | FDBD6638193B054F006D3BF6 /* InfoPlist.strings in Resources */,
451 | FD8B868E1BAD97DC00EA0D5D /* Testimage.jpg in Resources */,
452 | );
453 | runOnlyForDeploymentPostprocessing = 0;
454 | };
455 | /* End PBXResourcesBuildPhase section */
456 |
457 | /* Begin PBXShellScriptBuildPhase section */
458 | 22672DA7B2433B000CF2AAD2 /* Check Pods Manifest.lock */ = {
459 | isa = PBXShellScriptBuildPhase;
460 | buildActionMask = 2147483647;
461 | files = (
462 | );
463 | inputPaths = (
464 | );
465 | name = "Check Pods Manifest.lock";
466 | outputPaths = (
467 | );
468 | runOnlyForDeploymentPostprocessing = 0;
469 | shellPath = /bin/sh;
470 | 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";
471 | showEnvVarsInLog = 0;
472 | };
473 | 668C822E290F479BBF42B716 /* Check Pods Manifest.lock */ = {
474 | isa = PBXShellScriptBuildPhase;
475 | buildActionMask = 2147483647;
476 | files = (
477 | );
478 | inputPaths = (
479 | );
480 | name = "Check Pods Manifest.lock";
481 | outputPaths = (
482 | );
483 | runOnlyForDeploymentPostprocessing = 0;
484 | shellPath = /bin/sh;
485 | 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";
486 | showEnvVarsInLog = 0;
487 | };
488 | 70F9CA2574253E876D355FA3 /* Copy Pods Resources */ = {
489 | isa = PBXShellScriptBuildPhase;
490 | buildActionMask = 2147483647;
491 | files = (
492 | );
493 | inputPaths = (
494 | );
495 | name = "Copy Pods Resources";
496 | outputPaths = (
497 | );
498 | runOnlyForDeploymentPostprocessing = 0;
499 | shellPath = /bin/sh;
500 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
501 | showEnvVarsInLog = 0;
502 | };
503 | E172C5EA369C4663AD247B30 /* Check Pods Manifest.lock */ = {
504 | isa = PBXShellScriptBuildPhase;
505 | buildActionMask = 2147483647;
506 | files = (
507 | );
508 | inputPaths = (
509 | );
510 | name = "Check Pods Manifest.lock";
511 | outputPaths = (
512 | );
513 | runOnlyForDeploymentPostprocessing = 0;
514 | shellPath = /bin/sh;
515 | 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";
516 | showEnvVarsInLog = 0;
517 | };
518 | E9DCDA9D0E3F44EB95291CBC /* Copy Pods Resources */ = {
519 | isa = PBXShellScriptBuildPhase;
520 | buildActionMask = 2147483647;
521 | files = (
522 | );
523 | inputPaths = (
524 | );
525 | name = "Copy Pods Resources";
526 | outputPaths = (
527 | );
528 | runOnlyForDeploymentPostprocessing = 0;
529 | shellPath = /bin/sh;
530 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FSImageViewerTests/Pods-FSImageViewerTests-resources.sh\"\n";
531 | showEnvVarsInLog = 0;
532 | };
533 | F7A857B1B6AA493B8B48C1BD /* Copy Pods Resources */ = {
534 | isa = PBXShellScriptBuildPhase;
535 | buildActionMask = 2147483647;
536 | files = (
537 | );
538 | inputPaths = (
539 | );
540 | name = "Copy Pods Resources";
541 | outputPaths = (
542 | );
543 | runOnlyForDeploymentPostprocessing = 0;
544 | shellPath = /bin/sh;
545 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
546 | showEnvVarsInLog = 0;
547 | };
548 | /* End PBXShellScriptBuildPhase section */
549 |
550 | /* Begin PBXSourcesBuildPhase section */
551 | FD89E28C17CB99D900A41D91 /* Sources */ = {
552 | isa = PBXSourcesBuildPhase;
553 | buildActionMask = 2147483647;
554 | files = (
555 | FD89E2CA17CB9A0700A41D91 /* FSImageLoader.m in Sources */,
556 | FD89E2CB17CB9A0700A41D91 /* FSImageScrollView.m in Sources */,
557 | FD89E2CC17CB9A0700A41D91 /* FSImageTitleView.m in Sources */,
558 | FD89E2CD17CB9A0700A41D91 /* FSImageView.m in Sources */,
559 | FD89E2D217CB9A0E00A41D91 /* FSImageViewerViewController.m in Sources */,
560 | FD89E2D317CB9A0E00A41D91 /* FSPlaceholderImages.m in Sources */,
561 | FD0FEFBB17D77F1C00470082 /* FSBasicImageSource.m in Sources */,
562 | FD0FEFBF17D781EF00470082 /* FSBasicImage.m in Sources */,
563 | );
564 | runOnlyForDeploymentPostprocessing = 0;
565 | };
566 | FD89E2A117CB99F000A41D91 /* Sources */ = {
567 | isa = PBXSourcesBuildPhase;
568 | buildActionMask = 2147483647;
569 | files = (
570 | FD89E2B217CB99F000A41D91 /* main.m in Sources */,
571 | FD89E2B617CB99F000A41D91 /* FSAppDelegate.m in Sources */,
572 | FD89E2DD17CB9A4400A41D91 /* FSDemoViewController.m in Sources */,
573 | );
574 | runOnlyForDeploymentPostprocessing = 0;
575 | };
576 | FDBD662A193B054F006D3BF6 /* Sources */ = {
577 | isa = PBXSourcesBuildPhase;
578 | buildActionMask = 2147483647;
579 | files = (
580 | FDCB0B27193B956500F8B8A1 /* FSPlaceholderImagesTests.m in Sources */,
581 | FDBD663A193B054F006D3BF6 /* FSImageTitleViewTests.m in Sources */,
582 | FD8B86941BAD9C0B00EA0D5D /* FSBasicImageSourceTests.m in Sources */,
583 | FD8B86921BAD986B00EA0D5D /* FSTestImageHelper.m in Sources */,
584 | FD8B868C1BAD6F2400EA0D5D /* FSImageViewTests.m in Sources */,
585 | );
586 | runOnlyForDeploymentPostprocessing = 0;
587 | };
588 | /* End PBXSourcesBuildPhase section */
589 |
590 | /* Begin PBXTargetDependency section */
591 | FDBD663D193B054F006D3BF6 /* PBXTargetDependency */ = {
592 | isa = PBXTargetDependency;
593 | target = FD89E28F17CB99D900A41D91 /* FSImageViewer */;
594 | targetProxy = FDBD663C193B054F006D3BF6 /* PBXContainerItemProxy */;
595 | };
596 | FDD96CE317CB9B7000B66931 /* PBXTargetDependency */ = {
597 | isa = PBXTargetDependency;
598 | target = FD89E28F17CB99D900A41D91 /* FSImageViewer */;
599 | targetProxy = FDD96CE217CB9B7000B66931 /* PBXContainerItemProxy */;
600 | };
601 | FDF817091BAC2C75001337B4 /* PBXTargetDependency */ = {
602 | isa = PBXTargetDependency;
603 | target = FD89E2A417CB99F000A41D91 /* FSImageViewerDemo */;
604 | targetProxy = FDF817081BAC2C75001337B4 /* PBXContainerItemProxy */;
605 | };
606 | /* End PBXTargetDependency section */
607 |
608 | /* Begin PBXVariantGroup section */
609 | FD89E2AE17CB99F000A41D91 /* InfoPlist.strings */ = {
610 | isa = PBXVariantGroup;
611 | children = (
612 | FD89E2AF17CB99F000A41D91 /* en */,
613 | FD37CEC1181EBCDC00606D81 /* it */,
614 | FD37CEC2181EBCE000606D81 /* es */,
615 | FD37CEC3181EBCEC00606D81 /* fr */,
616 | FD37CEC4181EBCF400606D81 /* nl */,
617 | FD37CEC5181EC01700606D81 /* ru */,
618 | FD37CEC6181EC01E00606D81 /* de */,
619 | );
620 | name = InfoPlist.strings;
621 | sourceTree = "";
622 | };
623 | FDBD6636193B054F006D3BF6 /* InfoPlist.strings */ = {
624 | isa = PBXVariantGroup;
625 | children = (
626 | FDBD6637193B054F006D3BF6 /* en */,
627 | );
628 | name = InfoPlist.strings;
629 | sourceTree = "";
630 | };
631 | /* End PBXVariantGroup section */
632 |
633 | /* Begin XCBuildConfiguration section */
634 | FD89E29C17CB99D900A41D91 /* Debug */ = {
635 | isa = XCBuildConfiguration;
636 | buildSettings = {
637 | CLANG_ENABLE_OBJC_ARC = YES;
638 | CLANG_WARN_CONSTANT_CONVERSION = YES;
639 | CLANG_WARN_EMPTY_BODY = YES;
640 | CLANG_WARN_ENUM_CONVERSION = YES;
641 | CLANG_WARN_INT_CONVERSION = YES;
642 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
643 | COPY_PHASE_STRIP = NO;
644 | ENABLE_TESTABILITY = YES;
645 | GCC_DYNAMIC_NO_PIC = NO;
646 | GCC_OPTIMIZATION_LEVEL = 0;
647 | GCC_PREPROCESSOR_DEFINITIONS = (
648 | "DEBUG=1",
649 | "$(inherited)",
650 | "FB_REFERENCE_IMAGE_DIR=\"\\\"$(SOURCE_ROOT)/FSImageViewerTests/ReferenceImages\\\"\"",
651 | );
652 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
653 | GCC_TREAT_WARNINGS_AS_ERRORS = YES;
654 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
655 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
656 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
657 | GCC_WARN_UNUSED_VARIABLE = YES;
658 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
659 | ONLY_ACTIVE_ARCH = YES;
660 | SDKROOT = iphoneos;
661 | };
662 | name = Debug;
663 | };
664 | FD89E29D17CB99D900A41D91 /* Release */ = {
665 | isa = XCBuildConfiguration;
666 | buildSettings = {
667 | CLANG_ENABLE_OBJC_ARC = YES;
668 | CLANG_WARN_CONSTANT_CONVERSION = YES;
669 | CLANG_WARN_EMPTY_BODY = YES;
670 | CLANG_WARN_ENUM_CONVERSION = YES;
671 | CLANG_WARN_INT_CONVERSION = YES;
672 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
673 | COPY_PHASE_STRIP = YES;
674 | GCC_TREAT_WARNINGS_AS_ERRORS = YES;
675 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
676 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
677 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
678 | GCC_WARN_UNUSED_VARIABLE = YES;
679 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
680 | SDKROOT = iphoneos;
681 | VALIDATE_PRODUCT = YES;
682 | };
683 | name = Release;
684 | };
685 | FD89E29F17CB99D900A41D91 /* Debug */ = {
686 | isa = XCBuildConfiguration;
687 | baseConfigurationReference = 85A9CBC49B63FEB31F1448F5 /* Pods.debug.xcconfig */;
688 | buildSettings = {
689 | DSTROOT = /tmp/FSImageViewer.dst;
690 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
691 | GCC_PREFIX_HEADER = "FSImageViewer/FSImageViewer-Prefix.pch";
692 | PRODUCT_NAME = "$(TARGET_NAME)";
693 | SKIP_INSTALL = YES;
694 | };
695 | name = Debug;
696 | };
697 | FD89E2A017CB99D900A41D91 /* Release */ = {
698 | isa = XCBuildConfiguration;
699 | baseConfigurationReference = 2926F8C4CE2E738802DA8060 /* Pods.release.xcconfig */;
700 | buildSettings = {
701 | DSTROOT = /tmp/FSImageViewer.dst;
702 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
703 | GCC_PREFIX_HEADER = "FSImageViewer/FSImageViewer-Prefix.pch";
704 | PRODUCT_NAME = "$(TARGET_NAME)";
705 | SKIP_INSTALL = YES;
706 | };
707 | name = Release;
708 | };
709 | FD89E2BE17CB99F000A41D91 /* Debug */ = {
710 | isa = XCBuildConfiguration;
711 | baseConfigurationReference = 85A9CBC49B63FEB31F1448F5 /* Pods.debug.xcconfig */;
712 | buildSettings = {
713 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
714 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
715 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
716 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
717 | GCC_PREFIX_HEADER = "FSImageViewerDemo/FSImageViewerDemo-Prefix.pch";
718 | INFOPLIST_FILE = "FSImageViewerDemo/FSImageViewerDemo-Info.plist";
719 | PRODUCT_BUNDLE_IDENTIFIER = "de.felixschulze.${PRODUCT_NAME:rfc1034identifier}";
720 | PRODUCT_NAME = "$(TARGET_NAME)";
721 | TARGETED_DEVICE_FAMILY = "1,2";
722 | WRAPPER_EXTENSION = app;
723 | };
724 | name = Debug;
725 | };
726 | FD89E2BF17CB99F000A41D91 /* Release */ = {
727 | isa = XCBuildConfiguration;
728 | baseConfigurationReference = 2926F8C4CE2E738802DA8060 /* Pods.release.xcconfig */;
729 | buildSettings = {
730 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
731 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
732 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
733 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
734 | GCC_PREFIX_HEADER = "FSImageViewerDemo/FSImageViewerDemo-Prefix.pch";
735 | INFOPLIST_FILE = "FSImageViewerDemo/FSImageViewerDemo-Info.plist";
736 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
737 | PRODUCT_BUNDLE_IDENTIFIER = "de.felixschulze.${PRODUCT_NAME:rfc1034identifier}";
738 | PRODUCT_NAME = "$(TARGET_NAME)";
739 | TARGETED_DEVICE_FAMILY = "1,2";
740 | WRAPPER_EXTENSION = app;
741 | };
742 | name = Release;
743 | };
744 | FDBD663E193B054F006D3BF6 /* Debug */ = {
745 | isa = XCBuildConfiguration;
746 | baseConfigurationReference = F438121ACBFC9888194F99FE /* Pods-FSImageViewerTests.debug.xcconfig */;
747 | buildSettings = {
748 | BUNDLE_LOADER = "$(TEST_HOST)";
749 | CLANG_ENABLE_MODULES = YES;
750 | CLANG_WARN_BOOL_CONVERSION = YES;
751 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
752 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
753 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
754 | GCC_PREFIX_HEADER = "FSImageViewerTests/FSImageViewerTests-Prefix.pch";
755 | GCC_PREPROCESSOR_DEFINITIONS = (
756 | "DEBUG=1",
757 | "$(inherited)",
758 | );
759 | GCC_TREAT_WARNINGS_AS_ERRORS = NO;
760 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
761 | GCC_WARN_UNDECLARED_SELECTOR = YES;
762 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
763 | GCC_WARN_UNUSED_FUNCTION = YES;
764 | INFOPLIST_FILE = "FSImageViewerTests/FSImageViewerTests-Info.plist";
765 | PRODUCT_BUNDLE_IDENTIFIER = "de.felixschulze.${PRODUCT_NAME:rfc1034identifier}";
766 | PRODUCT_NAME = "$(TARGET_NAME)";
767 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FSImageViewerDemo.app/FSImageViewerDemo";
768 | WRAPPER_EXTENSION = xctest;
769 | };
770 | name = Debug;
771 | };
772 | FDBD663F193B054F006D3BF6 /* Release */ = {
773 | isa = XCBuildConfiguration;
774 | baseConfigurationReference = EAB987CD32B1D53A7F4A3B72 /* Pods-FSImageViewerTests.release.xcconfig */;
775 | buildSettings = {
776 | BUNDLE_LOADER = "$(TEST_HOST)";
777 | CLANG_ENABLE_MODULES = YES;
778 | CLANG_WARN_BOOL_CONVERSION = YES;
779 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
780 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
781 | ENABLE_NS_ASSERTIONS = NO;
782 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
783 | GCC_PREFIX_HEADER = "FSImageViewerTests/FSImageViewerTests-Prefix.pch";
784 | GCC_TREAT_WARNINGS_AS_ERRORS = NO;
785 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
786 | GCC_WARN_UNDECLARED_SELECTOR = YES;
787 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
788 | GCC_WARN_UNUSED_FUNCTION = YES;
789 | INFOPLIST_FILE = "FSImageViewerTests/FSImageViewerTests-Info.plist";
790 | PRODUCT_BUNDLE_IDENTIFIER = "de.felixschulze.${PRODUCT_NAME:rfc1034identifier}";
791 | PRODUCT_NAME = "$(TARGET_NAME)";
792 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FSImageViewerDemo.app/FSImageViewerDemo";
793 | WRAPPER_EXTENSION = xctest;
794 | };
795 | name = Release;
796 | };
797 | /* End XCBuildConfiguration section */
798 |
799 | /* Begin XCConfigurationList section */
800 | FD89E28B17CB99D900A41D91 /* Build configuration list for PBXProject "FSImageViewer" */ = {
801 | isa = XCConfigurationList;
802 | buildConfigurations = (
803 | FD89E29C17CB99D900A41D91 /* Debug */,
804 | FD89E29D17CB99D900A41D91 /* Release */,
805 | );
806 | defaultConfigurationIsVisible = 0;
807 | defaultConfigurationName = Release;
808 | };
809 | FD89E29E17CB99D900A41D91 /* Build configuration list for PBXNativeTarget "FSImageViewer" */ = {
810 | isa = XCConfigurationList;
811 | buildConfigurations = (
812 | FD89E29F17CB99D900A41D91 /* Debug */,
813 | FD89E2A017CB99D900A41D91 /* Release */,
814 | );
815 | defaultConfigurationIsVisible = 0;
816 | defaultConfigurationName = Release;
817 | };
818 | FD89E2BD17CB99F000A41D91 /* Build configuration list for PBXNativeTarget "FSImageViewerDemo" */ = {
819 | isa = XCConfigurationList;
820 | buildConfigurations = (
821 | FD89E2BE17CB99F000A41D91 /* Debug */,
822 | FD89E2BF17CB99F000A41D91 /* Release */,
823 | );
824 | defaultConfigurationIsVisible = 0;
825 | defaultConfigurationName = Release;
826 | };
827 | FDBD6640193B054F006D3BF6 /* Build configuration list for PBXNativeTarget "FSImageViewerTests" */ = {
828 | isa = XCConfigurationList;
829 | buildConfigurations = (
830 | FDBD663E193B054F006D3BF6 /* Debug */,
831 | FDBD663F193B054F006D3BF6 /* Release */,
832 | );
833 | defaultConfigurationIsVisible = 0;
834 | defaultConfigurationName = Release;
835 | };
836 | /* End XCConfigurationList section */
837 | };
838 | rootObject = FD89E28817CB99D900A41D91 /* Project object */;
839 | }
840 |
--------------------------------------------------------------------------------