diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..c929601 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Project** +This repo contains many projects, please state which project this issue is for. + +**Environment** +Please include at least the following details: +- Xcode version +- iOS version +- Device or simulator used to reproduce the bug + +**Describe the bug** +A clear and concise description of what the bug is. diff --git a/AdaptType/AdaptType.xcodeproj/project.pbxproj b/AdaptType/AdaptType.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5390100 --- /dev/null +++ b/AdaptType/AdaptType.xcodeproj/project.pbxproj @@ -0,0 +1,344 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 53ED33A52165588D005E895D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED33A42165588D005E895D /* AppDelegate.swift */; }; + 53ED33A72165588D005E895D /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED33A62165588D005E895D /* SettingsViewController.swift */; }; + 53ED33AA2165588D005E895D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53ED33A82165588D005E895D /* Main.storyboard */; }; + 53ED33AC2165588E005E895D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53ED33AB2165588E005E895D /* Assets.xcassets */; }; + 53ED33AF2165588E005E895D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53ED33AD2165588E005E895D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5379191D216B8B1F007E5997 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53ED33A12165588D005E895D /* AdaptType.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AdaptType.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53ED33A42165588D005E895D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53ED33A62165588D005E895D /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + 53ED33A92165588D005E895D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53ED33AB2165588E005E895D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53ED33AE2165588E005E895D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53ED33B02165588E005E895D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53ED339E2165588D005E895D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53ED33982165588D005E895D = { + isa = PBXGroup; + children = ( + 5379191D216B8B1F007E5997 /* README.md */, + 53ED33A32165588D005E895D /* AdaptType */, + 53ED33A22165588D005E895D /* Products */, + ); + sourceTree = ""; + }; + 53ED33A22165588D005E895D /* Products */ = { + isa = PBXGroup; + children = ( + 53ED33A12165588D005E895D /* AdaptType.app */, + ); + name = Products; + sourceTree = ""; + }; + 53ED33A32165588D005E895D /* AdaptType */ = { + isa = PBXGroup; + children = ( + 53ED33A42165588D005E895D /* AppDelegate.swift */, + 53ED33A62165588D005E895D /* SettingsViewController.swift */, + 53ED33A82165588D005E895D /* Main.storyboard */, + 53ED33AB2165588E005E895D /* Assets.xcassets */, + 53ED33AD2165588E005E895D /* LaunchScreen.storyboard */, + 53ED33B02165588E005E895D /* Info.plist */, + ); + path = AdaptType; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53ED33A02165588D005E895D /* AdaptType */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53ED33B32165588E005E895D /* Build configuration list for PBXNativeTarget "AdaptType" */; + buildPhases = ( + 53ED339D2165588D005E895D /* Sources */, + 53ED339E2165588D005E895D /* Frameworks */, + 53ED339F2165588D005E895D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AdaptType; + productName = AdaptType; + productReference = 53ED33A12165588D005E895D /* AdaptType.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53ED33992165588D005E895D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53ED33A02165588D005E895D = { + CreatedOnToolsVersion = 10.0; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 53ED339C2165588D005E895D /* Build configuration list for PBXProject "AdaptType" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53ED33982165588D005E895D; + productRefGroup = 53ED33A22165588D005E895D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53ED33A02165588D005E895D /* AdaptType */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53ED339F2165588D005E895D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53ED33AF2165588E005E895D /* LaunchScreen.storyboard in Resources */, + 53ED33AC2165588E005E895D /* Assets.xcassets in Resources */, + 53ED33AA2165588D005E895D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53ED339D2165588D005E895D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53ED33A72165588D005E895D /* SettingsViewController.swift in Sources */, + 53ED33A52165588D005E895D /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53ED33A82165588D005E895D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53ED33A92165588D005E895D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53ED33AD2165588E005E895D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53ED33AE2165588E005E895D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53ED33B12165588E005E895D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53ED33B22165588E005E895D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53ED33B42165588E005E895D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AdaptType/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AdaptType; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53ED33B52165588E005E895D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AdaptType/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AdaptType; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53ED339C2165588D005E895D /* Build configuration list for PBXProject "AdaptType" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53ED33B12165588E005E895D /* Debug */, + 53ED33B22165588E005E895D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53ED33B32165588E005E895D /* Build configuration list for PBXNativeTarget "AdaptType" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53ED33B42165588E005E895D /* Debug */, + 53ED33B52165588E005E895D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53ED33992165588D005E895D /* Project object */; +} diff --git a/AdaptType/AdaptType/AppDelegate.swift b/AdaptType/AdaptType/AppDelegate.swift new file mode 100644 index 0000000..85205c0 --- /dev/null +++ b/AdaptType/AdaptType/AppDelegate.swift @@ -0,0 +1,34 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/AdaptType/AdaptType/Assets.xcassets/AppIcon.appiconset/Contents.json b/AdaptType/AdaptType/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/AdaptType/AdaptType/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AdaptType/AdaptType/Assets.xcassets/Contents.json b/AdaptType/AdaptType/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AdaptType/AdaptType/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AdaptType/AdaptType/Base.lproj/LaunchScreen.storyboard b/AdaptType/AdaptType/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/AdaptType/AdaptType/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdaptType/AdaptType/Base.lproj/Main.storyboard b/AdaptType/AdaptType/Base.lproj/Main.storyboard new file mode 100644 index 0000000..8303d01 --- /dev/null +++ b/AdaptType/AdaptType/Base.lproj/Main.storyboard @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdaptType/AdaptType/Info.plist b/AdaptType/AdaptType/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/AdaptType/AdaptType/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AdaptType/AdaptType/SettingsViewController.swift b/AdaptType/AdaptType/SettingsViewController.swift new file mode 100644 index 0000000..c2a4310 --- /dev/null +++ b/AdaptType/AdaptType/SettingsViewController.swift @@ -0,0 +1,76 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class SettingsViewController: UIViewController { + @IBOutlet var stackView: UIStackView! + + let backgroundView: UIView = { + let view = UIView() + view.backgroundColor = .white + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + configureView(for: traitCollection) + } + + private func setupView() { + stackView.insertSubview(backgroundView, at: 0) + NSLayoutConstraint.activate([ + backgroundView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor), + backgroundView.topAnchor.constraint(equalTo: stackView.topAnchor), + backgroundView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor), + backgroundView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor) + ]) + } +} + +extension SettingsViewController { + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { + configureView(for: traitCollection) + } + } + + private func configureView(for traitCollection: UITraitCollection) { + let contentSize = traitCollection.preferredContentSizeCategory + if contentSize.isAccessibilityCategory { + stackView.axis = .vertical + stackView.alignment = .leading + } else { + stackView.axis = .horizontal + stackView.alignment = .center + } + } +} diff --git a/AdaptType/README.md b/AdaptType/README.md new file mode 100644 index 0000000..f9c4b69 --- /dev/null +++ b/AdaptType/README.md @@ -0,0 +1,5 @@ +# Making Space For Dynamic Type + +A case study that looks at how to implement the Larger Text screen from the Apple Settings App. See the following post for details: + ++ [Making Space For Dynamic Type](https://useyourloaf.com/blog/making-space-for-dynamic-type/) diff --git a/AdaptivePopover/AdaptivePopover.xcodeproj/project.pbxproj b/AdaptivePopover/AdaptivePopover.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e582a0a --- /dev/null +++ b/AdaptivePopover/AdaptivePopover.xcodeproj/project.pbxproj @@ -0,0 +1,340 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53BC63AE1C0A57E4009BFDDF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BC63AD1C0A57E4009BFDDF /* AppDelegate.swift */; }; + 53BC63B31C0A57E4009BFDDF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BC63B11C0A57E4009BFDDF /* Main.storyboard */; }; + 53BC63B51C0A57E4009BFDDF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53BC63B41C0A57E4009BFDDF /* Assets.xcassets */; }; + 53BC63B81C0A57E4009BFDDF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BC63B61C0A57E4009BFDDF /* LaunchScreen.storyboard */; }; + 53BC63C01C0A591A009BFDDF /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BC63BF1C0A591A009BFDDF /* RootViewController.swift */; }; + 53BC63C21C0A596C009BFDDF /* SimpleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BC63C11C0A596C009BFDDF /* SimpleViewController.swift */; }; + 53BC63C41C0A5F59009BFDDF /* SimpleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BC63C31C0A5F59009BFDDF /* SimpleTableViewController.swift */; }; + 53BC63C61C0A5F72009BFDDF /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BC63C51C0A5F72009BFDDF /* DetailViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53BC63AA1C0A57E4009BFDDF /* AdaptivePopover.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AdaptivePopover.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53BC63AD1C0A57E4009BFDDF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53BC63B41C0A57E4009BFDDF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53BC63B91C0A57E4009BFDDF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53BC63BF1C0A591A009BFDDF /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; + 53BC63C11C0A596C009BFDDF /* SimpleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleViewController.swift; sourceTree = ""; }; + 53BC63C31C0A5F59009BFDDF /* SimpleTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleTableViewController.swift; sourceTree = ""; }; + 53BC63C51C0A5F72009BFDDF /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 53FFA91A23C768C000EAFE01 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53FFA91D23C76E7D00EAFE01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53FFA91E23C76E7D00EAFE01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53BC63A71C0A57E4009BFDDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53BC63A11C0A57E4009BFDDF = { + isa = PBXGroup; + children = ( + 53FFA91A23C768C000EAFE01 /* README.md */, + 53BC63AC1C0A57E4009BFDDF /* AdaptivePopover */, + 53BC63AB1C0A57E4009BFDDF /* Products */, + ); + sourceTree = ""; + }; + 53BC63AB1C0A57E4009BFDDF /* Products */ = { + isa = PBXGroup; + children = ( + 53BC63AA1C0A57E4009BFDDF /* AdaptivePopover.app */, + ); + name = Products; + sourceTree = ""; + }; + 53BC63AC1C0A57E4009BFDDF /* AdaptivePopover */ = { + isa = PBXGroup; + children = ( + 53BC63AD1C0A57E4009BFDDF /* AppDelegate.swift */, + 53BC63B11C0A57E4009BFDDF /* Main.storyboard */, + 53BC63C31C0A5F59009BFDDF /* SimpleTableViewController.swift */, + 53BC63C51C0A5F72009BFDDF /* DetailViewController.swift */, + 53BC63C11C0A596C009BFDDF /* SimpleViewController.swift */, + 53BC63BF1C0A591A009BFDDF /* RootViewController.swift */, + 53BC63B41C0A57E4009BFDDF /* Assets.xcassets */, + 53BC63B61C0A57E4009BFDDF /* LaunchScreen.storyboard */, + 53BC63B91C0A57E4009BFDDF /* Info.plist */, + ); + path = AdaptivePopover; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53BC63A91C0A57E4009BFDDF /* AdaptivePopover */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53BC63BC1C0A57E4009BFDDF /* Build configuration list for PBXNativeTarget "AdaptivePopover" */; + buildPhases = ( + 53BC63A61C0A57E4009BFDDF /* Sources */, + 53BC63A71C0A57E4009BFDDF /* Frameworks */, + 53BC63A81C0A57E4009BFDDF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AdaptivePopover; + productName = AdaptivePopover; + productReference = 53BC63AA1C0A57E4009BFDDF /* AdaptivePopover.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53BC63A21C0A57E4009BFDDF /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0710; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53BC63A91C0A57E4009BFDDF = { + CreatedOnToolsVersion = 7.1.1; + DevelopmentTeam = LCC2J94N44; + }; + }; + }; + buildConfigurationList = 53BC63A51C0A57E4009BFDDF /* Build configuration list for PBXProject "AdaptivePopover" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53BC63A11C0A57E4009BFDDF; + productRefGroup = 53BC63AB1C0A57E4009BFDDF /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53BC63A91C0A57E4009BFDDF /* AdaptivePopover */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53BC63A81C0A57E4009BFDDF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BC63B81C0A57E4009BFDDF /* LaunchScreen.storyboard in Resources */, + 53BC63B51C0A57E4009BFDDF /* Assets.xcassets in Resources */, + 53BC63B31C0A57E4009BFDDF /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53BC63A61C0A57E4009BFDDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BC63C01C0A591A009BFDDF /* RootViewController.swift in Sources */, + 53BC63AE1C0A57E4009BFDDF /* AppDelegate.swift in Sources */, + 53BC63C61C0A5F72009BFDDF /* DetailViewController.swift in Sources */, + 53BC63C21C0A596C009BFDDF /* SimpleViewController.swift in Sources */, + 53BC63C41C0A5F59009BFDDF /* SimpleTableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53BC63B11C0A57E4009BFDDF /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53FFA91D23C76E7D00EAFE01 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53BC63B61C0A57E4009BFDDF /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53FFA91E23C76E7D00EAFE01 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53BC63BA1C0A57E4009BFDDF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53BC63BB1C0A57E4009BFDDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53BC63BD1C0A57E4009BFDDF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AdaptivePopover/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AdaptivePopover; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 53BC63BE1C0A57E4009BFDDF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AdaptivePopover/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AdaptivePopover; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53BC63A51C0A57E4009BFDDF /* Build configuration list for PBXProject "AdaptivePopover" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BC63BA1C0A57E4009BFDDF /* Debug */, + 53BC63BB1C0A57E4009BFDDF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BC63BC1C0A57E4009BFDDF /* Build configuration list for PBXNativeTarget "AdaptivePopover" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BC63BD1C0A57E4009BFDDF /* Debug */, + 53BC63BE1C0A57E4009BFDDF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53BC63A21C0A57E4009BFDDF /* Project object */; +} diff --git a/AdaptivePopover/AdaptivePopover/AppDelegate.swift b/AdaptivePopover/AdaptivePopover/AppDelegate.swift new file mode 100644 index 0000000..9833a11 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/AppDelegate.swift @@ -0,0 +1,40 @@ +// +// AppDelegate.swift +// AdaptivePopover +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} + diff --git a/AdaptivePopover/AdaptivePopover/Assets.xcassets/AppIcon.appiconset/Contents.json b/AdaptivePopover/AdaptivePopover/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AdaptivePopover/AdaptivePopover/Base.lproj/LaunchScreen.storyboard b/AdaptivePopover/AdaptivePopover/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfec1a2 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdaptivePopover/AdaptivePopover/Base.lproj/Main.storyboard b/AdaptivePopover/AdaptivePopover/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e1d5a06 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/Base.lproj/Main.storyboard @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdaptivePopover/AdaptivePopover/DetailViewController.swift b/AdaptivePopover/AdaptivePopover/DetailViewController.swift new file mode 100644 index 0000000..dbfe95e --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/DetailViewController.swift @@ -0,0 +1,47 @@ +// +// DetailViewController.swift +// AdaptivePopover +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class DetailViewController: UIViewController { + + @IBOutlet private weak var detailLabel: UILabel! + + var detailText = "No detail" + + override func viewDidLoad() { + super.viewDidLoad() + detailLabel.text = detailText + title = detailText + } +} diff --git a/AdaptivePopover/AdaptivePopover/Info.plist b/AdaptivePopover/AdaptivePopover/Info.plist new file mode 100644 index 0000000..26e2b70 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AdaptivePopover/AdaptivePopover/RootViewController.swift b/AdaptivePopover/AdaptivePopover/RootViewController.swift new file mode 100644 index 0000000..3afb47c --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/RootViewController.swift @@ -0,0 +1,104 @@ +// +// RootViewController.swift +// AdaptivePopover +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class RootViewController: UIViewController { + @IBOutlet var simpleButton: UIButton! + @IBOutlet var embeddedButton: UIButton! + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + switch segue.identifier { + case "SimpleSegue"?: + let simplePPC = segue.destination.popoverPresentationController + simplePPC?.delegate = self + simplePPC?.sourceView = simpleButton + simplePPC?.sourceRect = simpleButton.bounds + case "EmbeddedSegue"?: + let embeddedPPC = segue.destination.popoverPresentationController + embeddedPPC?.delegate = self + embeddedPPC?.sourceView = embeddedButton + embeddedPPC?.sourceRect = embeddedButton.bounds + default: + fatalError("Unknown segue: \(segue.identifier ?? "Unknown")") + } + } +} + +// MARK: UIPopoverPresentationControllerDelegate + +extension RootViewController: UIPopoverPresentationControllerDelegate { + // In modal presentation we need to add a button to our popover + // to allow it to be dismissed. Handle the situation where + // our popover may be embedded in a navigation controller + + func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? { + if style == .none { + return controller.presentedViewController + } + + let navigationController: UINavigationController = { + guard let navigationController = controller.presentedViewController as? UINavigationController else { + return UINavigationController(rootViewController: controller.presentedViewController) + } + return navigationController + }() + + addDismissButton(navigationController) + return navigationController + } + + // Check for when we present in a non modal style and remove the + // the dismiss button from the navigation bar. + + func presentationController(_ presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?) { + if style == .none, + let navController = presentationController.presentedViewController as? UINavigationController { + removeDismissButton(navController) + } + } + + @objc private func didDismissPresentedView() { + presentedViewController?.dismiss(animated: true, completion: nil) + } + + private func addDismissButton(_ navigationController: UINavigationController) { + let rootViewController = navigationController.viewControllers[0] + rootViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(didDismissPresentedView)) + } + + private func removeDismissButton(_ navigationController: UINavigationController) { + let rootViewController = navigationController.viewControllers[0] + rootViewController.navigationItem.leftBarButtonItem = nil + } +} diff --git a/AdaptivePopover/AdaptivePopover/SimpleTableViewController.swift b/AdaptivePopover/AdaptivePopover/SimpleTableViewController.swift new file mode 100644 index 0000000..a41c123 --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/SimpleTableViewController.swift @@ -0,0 +1,63 @@ +// +// SimpleTableViewController.swift +// AdaptivePopover +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class SimpleTableViewController: UIViewController { + @IBOutlet var tableView: UITableView! + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "ShowDetailSegue", + let sender = sender as? UITableViewCell, + let indexPath = tableView.indexPath(for: sender), + let detailViewController = segue.destination as? DetailViewController { + detailViewController.detailText = "Item \(indexPath.row)" + } + } +} + +extension SimpleTableViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 10 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleCell", for: indexPath) + cell.textLabel?.text = "Item \(indexPath.row)" + return cell + } +} diff --git a/AdaptivePopover/AdaptivePopover/SimpleViewController.swift b/AdaptivePopover/AdaptivePopover/SimpleViewController.swift new file mode 100644 index 0000000..384d46d --- /dev/null +++ b/AdaptivePopover/AdaptivePopover/SimpleViewController.swift @@ -0,0 +1,38 @@ +// +// SimpleViewController.swift +// AdaptivePopover +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class SimpleViewController: UIViewController { + +} diff --git a/AdaptivePopover/README.md b/AdaptivePopover/README.md new file mode 100644 index 0000000..2f2a4be --- /dev/null +++ b/AdaptivePopover/README.md @@ -0,0 +1,10 @@ +# AdaptivePopover - Adapting popovers to size classes + ++ Version 2.0 09 Jan 2020 Updated for Xcode 11, Swift 5 and iOS 13 ++ Version 1.0 30 Nov 2015 Initial version. + +Example of how to use the `UIPopoverPresentationController` delegate +protocol to adapt a popover to compact size classes. See the following +post for further details: + ++ [Making Popovers Adapt to Size Classes](https://useyourloaf.com/blog/making-popovers-adapt-to-size-classes/) diff --git a/AirPrinter/AirPrinter/WebViewController.xib b/AirPrinter/AirPrinter/WebViewController.xib deleted file mode 100644 index b28d757..0000000 --- a/AirPrinter/AirPrinter/WebViewController.xib +++ /dev/null @@ -1,177 +0,0 @@ - - - - 1056 - 11A511 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBProxyObject - IBUIWebView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - {240, 128} - - - _NS:667 - - 1 - MSAxIDEAA - - IBCocoaTouchFramework - YES - - - - - YES - - - webView - - - - 5 - - - - delegate - - - - 6 - - - - view - - - - 7 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - Web View - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 4.IBPluginDependency - - - YES - WebViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 7 - - - - YES - - WebViewController - UIViewController - - webView - UIWebView - - - webView - - webView - UIWebView - - - - IBProjectSource - ./Classes/WebViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/AirPrinter/AirPrinter/en.lproj/MainWindow.xib b/AirPrinter/AirPrinter/en.lproj/MainWindow.xib deleted file mode 100644 index ba438d9..0000000 --- a/AirPrinter/AirPrinter/en.lproj/MainWindow.xib +++ /dev/null @@ -1,331 +0,0 @@ - - - - 1024 - 11A511 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBProxyObject - IBUINavigationController - IBUIViewController - IBUICustomObject - IBUIBarButtonItem - IBUIWindow - IBUINavigationBar - IBUINavigationItem - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - IBCocoaTouchFramework - - - - 1316 - - {320, 480} - - - - 1 - MSAxIDEAA - - NO - NO - - IBCocoaTouchFramework - YES - - - - - 1 - 1 - - IBCocoaTouchFramework - NO - - - 256 - {0, 0} - NO - YES - YES - IBCocoaTouchFramework - - - YES - - - - AirPrinter - - Home - IBCocoaTouchFramework - 1 - - IBCocoaTouchFramework - - - RootViewController - - - 1 - 1 - - IBCocoaTouchFramework - NO - - - - - - - YES - - - delegate - - - - 4 - - - - window - - - - 5 - - - - navigationController - - - - 15 - - - - - YES - - 0 - - - - - - 2 - - - YES - - - - - -1 - - - File's Owner - - - 3 - - - - - -2 - - - - - 9 - - - YES - - - - - - - 11 - - - - - 13 - - - YES - - - - - - 14 - - - YES - - - - - - 17 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 11.IBPluginDependency - 13.CustomClassName - 13.IBPluginDependency - 14.IBPluginDependency - 17.IBPluginDependency - 2.IBAttributePlaceholdersKey - 2.IBPluginDependency - 3.CustomClassName - 3.IBPluginDependency - 9.IBPluginDependency - - - YES - UIApplication - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RootViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - YES - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - AirPrinterAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 17 - - - - YES - - AirPrinterAppDelegate - NSObject - - YES - - YES - navigationController - window - - - YES - UINavigationController - UIWindow - - - - YES - - YES - navigationController - window - - - YES - - navigationController - UINavigationController - - - window - UIWindow - - - - - IBProjectSource - ./Classes/AirPrinterAppDelegate.h - - - - RootViewController - UIViewController - - IBProjectSource - ./Classes/RootViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/AirPrinter/AirPrinter/en.lproj/RootViewController.xib b/AirPrinter/AirPrinter/en.lproj/RootViewController.xib deleted file mode 100644 index 6768cbf..0000000 --- a/AirPrinter/AirPrinter/en.lproj/RootViewController.xib +++ /dev/null @@ -1,170 +0,0 @@ - - - - 784 - 11A511 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - IBProxyObject - IBUIView - IBUITextField - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - - - 290 - {{20, 71}, {280, 31}} - - - - _NS:294 - NO - YES - IBCocoaTouchFramework - 0 - http://apple.com - 3 - Enter a web site URL - - 3 - MAA - - 2 - - - YES - 17 - - 1 - 3 - 1 - YES - IBCocoaTouchFramework - - 1 - - - {320, 460} - - - - _NS:180 - - 1 - MC41IDAgMC41AA - - IBCocoaTouchFramework - - - - - - - view - - - - 10 - - - - delegate - - - - 11 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - - - - - - 8 - - - - - - - RootViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 11 - - - - - RootViewController - UIViewController - - IBProjectSource - ./Classes/RootViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 534 - - diff --git a/AirPrinter/AirPrinter/iPad/en.lproj/MainWindow-iPad.xib b/AirPrinter/AirPrinter/iPad/en.lproj/MainWindow-iPad.xib deleted file mode 100644 index c56e8f8..0000000 --- a/AirPrinter/AirPrinter/iPad/en.lproj/MainWindow-iPad.xib +++ /dev/null @@ -1,349 +0,0 @@ - - - - 1056 - 11A511 - 1617 - 1138 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 534 - - - YES - IBProxyObject - IBUINavigationController - IBUIViewController - IBUICustomObject - IBUIBarButtonItem - IBUIWindow - IBUINavigationBar - IBUINavigationItem - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - IBIPadFramework - - - - 1316 - - {768, 1024} - - - - - 1 - MSAxIDEAA - - NO - NO - - 2 - - IBIPadFramework - YES - - - - - 1 - 1 - - IBIPadFramework - NO - - - 256 - {0, 0} - NO - YES - YES - IBIPadFramework - - - YES - - - - AirPrinter - - Home - IBIPadFramework - 1 - - IBIPadFramework - - - RootViewController - - - 1 - 1 - - IBIPadFramework - NO - - - - - - - YES - - - delegate - - - - 4 - - - - window - - - - 5 - - - - navigationController - - - - 15 - - - - - YES - - 0 - - - - - - 2 - - - YES - - - - - -1 - - - File's Owner - - - 3 - - - - - -2 - - - - - 9 - - - YES - - - - - - - 11 - - - - - 13 - - - YES - - - - - - 14 - - - YES - - - - - - 17 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 11.IBPluginDependency - 13.CustomClassName - 13.IBLastUsedUIStatusBarStylesToTargetRuntimesMap - 13.IBPluginDependency - 14.IBPluginDependency - 17.IBPluginDependency - 2.IBAttributePlaceholdersKey - 2.IBLastUsedUIStatusBarStylesToTargetRuntimesMap - 2.IBPluginDependency - 3.CustomClassName - 3.IBPluginDependency - 9.IBLastUsedUIStatusBarStylesToTargetRuntimesMap - 9.IBPluginDependency - - - YES - UIApplication - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RootViewController - - IBCocoaTouchFramework - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - YES - - - - - IBCocoaTouchFramework - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - AirPrinterAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - IBCocoaTouchFramework - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 17 - - - - YES - - AirPrinterAppDelegate - NSObject - - YES - - YES - navigationController - window - - - YES - UINavigationController - UIWindow - - - - YES - - YES - navigationController - window - - - YES - - navigationController - UINavigationController - - - window - UIWindow - - - - - IBProjectSource - ./Classes/AirPrinterAppDelegate.h - - - - RootViewController - UIViewController - - IBProjectSource - ./Classes/RootViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 534 - - diff --git a/AlertController/AlertController.xcodeproj/project.pbxproj b/AlertController/AlertController.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5ac5e6a --- /dev/null +++ b/AlertController/AlertController.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 5307C7D519B6245B00CFD37F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5307C7D419B6245B00CFD37F /* main.m */; }; + 5307C7D819B6245B00CFD37F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5307C7D719B6245B00CFD37F /* AppDelegate.m */; }; + 5307C7DB19B6245B00CFD37F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5307C7DA19B6245B00CFD37F /* ViewController.m */; }; + 5307C7DE19B6245B00CFD37F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5307C7DC19B6245B00CFD37F /* Main.storyboard */; }; + 5307C7E019B6245B00CFD37F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5307C7DF19B6245B00CFD37F /* Images.xcassets */; }; + 53AF7FFA1AECFD9C00683F34 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 53AF7FF91AECFD9C00683F34 /* README */; }; + 53B2CD6023C8E61A007FF91F /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53B2CD6223C8E61A007FF91F /* Launch Screen.storyboard */; }; + 53D5575019B66F5D005EAFDF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53D5574E19B66F5D005EAFDF /* Localizable.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5307C7CF19B6245B00CFD37F /* AlertController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlertController.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5307C7D319B6245B00CFD37F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5307C7D419B6245B00CFD37F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5307C7D619B6245B00CFD37F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5307C7D719B6245B00CFD37F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5307C7D919B6245B00CFD37F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 5307C7DA19B6245B00CFD37F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 5307C7DD19B6245B00CFD37F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5307C7DF19B6245B00CFD37F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53AF7FF91AECFD9C00683F34 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + 53B2CD6123C8E61A007FF91F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Launch Screen.storyboard"; sourceTree = ""; }; + 53D5574F19B66F5D005EAFDF /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5307C7CC19B6245B00CFD37F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5307C7C619B6245B00CFD37F = { + isa = PBXGroup; + children = ( + 53AF7FF91AECFD9C00683F34 /* README */, + 5307C7D119B6245B00CFD37F /* AlertController */, + 5307C7D019B6245B00CFD37F /* Products */, + ); + sourceTree = ""; + }; + 5307C7D019B6245B00CFD37F /* Products */ = { + isa = PBXGroup; + children = ( + 5307C7CF19B6245B00CFD37F /* AlertController.app */, + ); + name = Products; + sourceTree = ""; + }; + 5307C7D119B6245B00CFD37F /* AlertController */ = { + isa = PBXGroup; + children = ( + 5307C7D619B6245B00CFD37F /* AppDelegate.h */, + 5307C7D719B6245B00CFD37F /* AppDelegate.m */, + 5307C7D919B6245B00CFD37F /* ViewController.h */, + 5307C7DA19B6245B00CFD37F /* ViewController.m */, + 5307C7DC19B6245B00CFD37F /* Main.storyboard */, + 53B2CD6223C8E61A007FF91F /* Launch Screen.storyboard */, + 5307C7DF19B6245B00CFD37F /* Images.xcassets */, + 5307C7D219B6245B00CFD37F /* Supporting Files */, + ); + path = AlertController; + sourceTree = ""; + }; + 5307C7D219B6245B00CFD37F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5307C7D319B6245B00CFD37F /* Info.plist */, + 5307C7D419B6245B00CFD37F /* main.m */, + 53D5574E19B66F5D005EAFDF /* Localizable.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5307C7CE19B6245B00CFD37F /* AlertController */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5307C7EF19B6245B00CFD37F /* Build configuration list for PBXNativeTarget "AlertController" */; + buildPhases = ( + 5307C7CB19B6245B00CFD37F /* Sources */, + 5307C7CC19B6245B00CFD37F /* Frameworks */, + 5307C7CD19B6245B00CFD37F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AlertController; + productName = AlertController; + productReference = 5307C7CF19B6245B00CFD37F /* AlertController.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5307C7C719B6245B00CFD37F /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5307C7CE19B6245B00CFD37F = { + CreatedOnToolsVersion = 6.0; + }; + }; + }; + buildConfigurationList = 5307C7CA19B6245B00CFD37F /* Build configuration list for PBXProject "AlertController" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5307C7C619B6245B00CFD37F; + productRefGroup = 5307C7D019B6245B00CFD37F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5307C7CE19B6245B00CFD37F /* AlertController */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5307C7CD19B6245B00CFD37F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AF7FFA1AECFD9C00683F34 /* README in Resources */, + 5307C7DE19B6245B00CFD37F /* Main.storyboard in Resources */, + 53D5575019B66F5D005EAFDF /* Localizable.strings in Resources */, + 53B2CD6023C8E61A007FF91F /* Launch Screen.storyboard in Resources */, + 5307C7E019B6245B00CFD37F /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5307C7CB19B6245B00CFD37F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5307C7DB19B6245B00CFD37F /* ViewController.m in Sources */, + 5307C7D819B6245B00CFD37F /* AppDelegate.m in Sources */, + 5307C7D519B6245B00CFD37F /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5307C7DC19B6245B00CFD37F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5307C7DD19B6245B00CFD37F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53B2CD6223C8E61A007FF91F /* Launch Screen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53B2CD6123C8E61A007FF91F /* Base */, + ); + name = "Launch Screen.storyboard"; + sourceTree = ""; + }; + 53D5574E19B66F5D005EAFDF /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 53D5574F19B66F5D005EAFDF /* en */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5307C7ED19B6245B00CFD37F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5307C7EE19B6245B00CFD37F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5307C7F019B6245B00CFD37F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AlertController/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 5307C7F119B6245B00CFD37F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AlertController/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5307C7CA19B6245B00CFD37F /* Build configuration list for PBXProject "AlertController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5307C7ED19B6245B00CFD37F /* Debug */, + 5307C7EE19B6245B00CFD37F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5307C7EF19B6245B00CFD37F /* Build configuration list for PBXNativeTarget "AlertController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5307C7F019B6245B00CFD37F /* Debug */, + 5307C7F119B6245B00CFD37F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5307C7C719B6245B00CFD37F /* Project object */; +} diff --git a/AlertController/AlertController/AppDelegate.h b/AlertController/AlertController/AppDelegate.h new file mode 100644 index 0000000..660ba13 --- /dev/null +++ b/AlertController/AlertController/AppDelegate.h @@ -0,0 +1,42 @@ +// +// AppDelegate.h +// AlertController +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end + diff --git a/AlertController/AlertController/AppDelegate.m b/AlertController/AlertController/AppDelegate.m new file mode 100644 index 0000000..6cbb7f9 --- /dev/null +++ b/AlertController/AlertController/AppDelegate.m @@ -0,0 +1,39 @@ +// +// AppDelegate.m +// AlertController +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" + +@implementation AppDelegate + +@end diff --git a/AlertController/AlertController/Base.lproj/Launch Screen.storyboard b/AlertController/AlertController/Base.lproj/Launch Screen.storyboard new file mode 100644 index 0000000..02419c6 --- /dev/null +++ b/AlertController/AlertController/Base.lproj/Launch Screen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AlertController/AlertController/Base.lproj/Main.storyboard b/AlertController/AlertController/Base.lproj/Main.storyboard new file mode 100644 index 0000000..13541af --- /dev/null +++ b/AlertController/AlertController/Base.lproj/Main.storyboard @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AlertController/AlertController/Images.xcassets/AppIcon.appiconset/Contents.json b/AlertController/AlertController/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/AlertController/AlertController/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AlertController/AlertController/Images.xcassets/Contents.json b/AlertController/AlertController/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AlertController/AlertController/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AlertController/AlertController/Info.plist b/AlertController/AlertController/Info.plist new file mode 100644 index 0000000..3af6cd7 --- /dev/null +++ b/AlertController/AlertController/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Launch Screen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AlertController/AlertController/ViewController.h b/AlertController/AlertController/ViewController.h new file mode 100644 index 0000000..0d45b56 --- /dev/null +++ b/AlertController/AlertController/ViewController.h @@ -0,0 +1,38 @@ +// +// ViewController.h +// AlertController +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface ViewController : UIViewController + +@end diff --git a/AlertController/AlertController/ViewController.m b/AlertController/AlertController/ViewController.m new file mode 100644 index 0000000..ca679f3 --- /dev/null +++ b/AlertController/AlertController/ViewController.m @@ -0,0 +1,237 @@ +// +// ViewController.m +// AlertController +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "ViewController.h" + +@implementation ViewController + +#pragma mark - +#pragma mark === Lifecyle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - +#pragma mark === IBAction methods === +#pragma mark - + +- (IBAction)showBasicAlertView:(UIButton *)sender +{ + NSString *alertTitle = NSLocalizedString(@"BasicAlertTitle", @"Basic Alert Style"); + NSString *alertMessage = NSLocalizedString(@"BasicAlertMessage", @"Basic Alert With Buttons"); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitle + message:alertMessage + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *action) + { + NSLog(@"Cancel action"); + }]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK action") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) + { + NSLog(@"OK action"); + }]; + + [alertController addAction:cancelAction]; + [alertController addAction:okAction]; + + [self presentViewController:alertController animated:YES completion:nil]; +} + +- (IBAction)showDestructiveAlertView:(UIButton *)sender +{ + NSString *alertTitle = NSLocalizedString(@"BasicAlertTitle", @"Basic Alert Style"); + NSString *alertMessage = NSLocalizedString(@"BasicAlertMessage", @"Basic Alert With Buttons"); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitle + message:alertMessage + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *resetAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Reset", @"Reset action") + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction *action) + { + NSLog(@"Reset action"); + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *action) + { + NSLog(@"Cancel action"); + }]; + + [alertController addAction:resetAction]; + [alertController addAction:cancelAction]; + + [self presentViewController:alertController animated:YES completion:nil]; +} + +- (IBAction)showTextAlertView:(UIButton *)sender +{ + NSString *alertTitle = NSLocalizedString(@"TextAlertTitle", @"Text Input Alert"); + NSString *alertMessage = NSLocalizedString(@"TextAlertMessage", @"Plain and secure text input"); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitle + message:alertMessage + preferredStyle:UIAlertControllerStyleAlert]; + + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) + { + textField.placeholder = NSLocalizedString(@"LoginPlaceholder", @"Login"); + [textField addTarget:self + action:@selector(alertTextFieldDidChange:) + forControlEvents:UIControlEventEditingChanged]; + }]; + + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) + { + textField.placeholder = NSLocalizedString(@"PasswordPlaceholder", @"Password"); + textField.secureTextEntry = YES; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *action) + { + NSLog(@"Cancel action"); + }]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK action") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) + { + UITextField *login = alertController.textFields.firstObject; + UITextField *password = alertController.textFields.lastObject; + + NSLog(@"OK action"); + NSLog(@"Login value: %@",login.text); + NSLog(@"Password value: %@",password.text); + }]; + + okAction.enabled = NO; + [alertController addAction:cancelAction]; + [alertController addAction:okAction]; + + [self presentViewController:alertController animated:YES completion:nil]; +} + +- (IBAction)showActionSheet:(UIButton *)sender +{ + NSString *alertTitle = NSLocalizedString(@"ActionTitle", @"Archive or Delete Data"); + NSString *alertMessage = NSLocalizedString(@"ActionMessage", @"Deleted data cannot be undone"); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:alertTitle + message:alertMessage + preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") + style:UIAlertActionStyleCancel + handler:^(UIAlertAction *action) + { + NSLog(@"Cancel action"); + }]; + + UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Delete", @"Delete action") + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction *action) + { + NSLog(@"Delete action"); + }]; + + UIAlertAction *archiveAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Archive", @"Archive action") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) + { + NSLog(@"Archive action"); + }]; + + [alertController addAction:cancelAction]; + [alertController addAction:deleteAction]; + [alertController addAction:archiveAction]; + + UIPopoverPresentationController *popover = alertController.popoverPresentationController; + if (popover) + { + popover.sourceView = sender; + popover.sourceRect = sender.bounds; + popover.permittedArrowDirections = UIPopoverArrowDirectionAny; + } + + [self presentViewController:alertController animated:YES completion:nil]; +} + +#pragma mark - +#pragma mark === UITextField - UIControlEventEditingChanged === +#pragma mark - + +- (void)alertTextFieldDidChange:(UITextField *)sender +{ + UIAlertController *alertController = (UIAlertController *)self.presentedViewController; + if (alertController) + { + UITextField *login = alertController.textFields.firstObject; + UIAlertAction *okAction = alertController.actions.lastObject; + okAction.enabled = login.text.length > 2; + } +} + +#pragma mark - +#pragma mark === UIApplicationDidEnterBackgroundNotification === +#pragma mark - + +- (void)didEnterBackground:(NSNotification *)notification +{ + [self.presentedViewController dismissViewControllerAnimated:NO completion:nil]; +} + +@end diff --git a/AlertController/AlertController/en.lproj/Localizable.strings b/AlertController/AlertController/en.lproj/Localizable.strings new file mode 100644 index 0000000..2ec1f8d Binary files /dev/null and b/AlertController/AlertController/en.lproj/Localizable.strings differ diff --git a/AlertController/AlertController/main.m b/AlertController/AlertController/main.m new file mode 100644 index 0000000..9098c18 --- /dev/null +++ b/AlertController/AlertController/main.m @@ -0,0 +1,42 @@ +// +// main.m +// AlertController +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/AlertController/README b/AlertController/README new file mode 100644 index 0000000..3b9896a --- /dev/null +++ b/AlertController/README @@ -0,0 +1,13 @@ +======================================================================= +AlertController - Sample code for UIAlertController + +Version 1.1 26 April 2015 Use target-action for text field changes +Version 1.0 05 September 2014 Initial version. +======================================================================= + +Example code covering the use of UIAlertController to create alert and +action sheet views. The UIAlertController class was introduced in iOS 8 +as a replacement for UIAlertView and UIActionSheet. Full details in the +following post: + +https://useyourloaf.com/blog/uialertcontroller-changes-in-ios-8/ diff --git a/AlertView/AlertView/en.lproj/UYLViewController.xib b/AlertView/AlertView/en.lproj/UYLViewController.xib deleted file mode 100644 index 7de4aa1..0000000 --- a/AlertView/AlertView/en.lproj/UYLViewController.xib +++ /dev/null @@ -1,326 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBUIButton - IBUIView - IBUILabel - IBProxyObject - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 292 - {{20, 118}, {280, 37}} - - - _NS:225 - NO - IBCocoaTouchFramework - 0 - 0 - 1 - Default Style - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{20, 190}, {280, 37}} - - - _NS:225 - NO - IBCocoaTouchFramework - 0 - 0 - 1 - Secure Text Input - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 262}, {280, 37}} - - - _NS:225 - NO - IBCocoaTouchFramework - 0 - 0 - 1 - Plain Text Input - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 336}, {280, 37}} - - - _NS:225 - NO - IBCocoaTouchFramework - 0 - 0 - 1 - Login and Password - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 20}, {280, 46}} - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - UIAlertViewStyle - - 1 - MSAxIDAAA - - - 1 - 10 - 1 - - 1 - 20 - - - Helvetica - 20 - 16 - - - - {{0, 20}, {320, 460}} - - - - - 1 - MC41IDAgMC41AA - - NO - - IBCocoaTouchFramework - - - - - - - view - - - - 7 - - - - showDefaultAlertView: - - - 7 - - 13 - - - - showSecureTextAlertView: - - - 7 - - 14 - - - - showPlainTextAlertView: - - - 7 - - 15 - - - - showLoginPassAlertView: - - - 7 - - 16 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - - - - - - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 12 - - - - - - - UYLViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 16 - - - - - UYLViewController - UIViewController - - IBProjectSource - ./Classes/UYLViewController.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - 933 - - diff --git a/AllVisible/AllVisible.xcodeproj/project.pbxproj b/AllVisible/AllVisible.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6c1007d --- /dev/null +++ b/AllVisible/AllVisible.xcodeproj/project.pbxproj @@ -0,0 +1,486 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53AA2EB61DA2A957008EBF84 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2EB51DA2A957008EBF84 /* AppDelegate.swift */; }; + 53AA2EB81DA2A957008EBF84 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2EB71DA2A957008EBF84 /* MasterViewController.swift */; }; + 53AA2EBA1DA2A957008EBF84 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2EB91DA2A957008EBF84 /* DetailViewController.swift */; }; + 53AA2EBD1DA2A957008EBF84 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EBB1DA2A957008EBF84 /* Main.storyboard */; }; + 53AA2EBF1DA2A957008EBF84 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EBE1DA2A957008EBF84 /* Assets.xcassets */; }; + 53AA2EC21DA2A957008EBF84 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EC01DA2A957008EBF84 /* LaunchScreen.storyboard */; }; + 53AA2ED11DA2AE09008EBF84 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2ED01DA2AE09008EBF84 /* main.m */; }; + 53AA2ED41DA2AE09008EBF84 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2ED31DA2AE09008EBF84 /* AppDelegate.m */; }; + 53AA2ED71DA2AE09008EBF84 /* MasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2ED61DA2AE09008EBF84 /* MasterViewController.m */; }; + 53AA2EDA1DA2AE09008EBF84 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53AA2ED91DA2AE09008EBF84 /* DetailViewController.m */; }; + 53AA2EDD1DA2AE09008EBF84 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EDB1DA2AE09008EBF84 /* Main.storyboard */; }; + 53AA2EDF1DA2AE09008EBF84 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EDE1DA2AE09008EBF84 /* Assets.xcassets */; }; + 53AA2EE21DA2AE09008EBF84 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AA2EE01DA2AE09008EBF84 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 531225F81DA2E4440040CE8B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53AA2EB21DA2A957008EBF84 /* AllVisible.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AllVisible.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53AA2EB51DA2A957008EBF84 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53AA2EB71DA2A957008EBF84 /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + 53AA2EB91DA2A957008EBF84 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 53AA2EBC1DA2A957008EBF84 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53AA2EBE1DA2A957008EBF84 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53AA2EC11DA2A957008EBF84 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53AA2EC31DA2A957008EBF84 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53AA2ECD1DA2AE09008EBF84 /* AllVisibleObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AllVisibleObjC.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53AA2ED01DA2AE09008EBF84 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53AA2ED21DA2AE09008EBF84 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 53AA2ED31DA2AE09008EBF84 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 53AA2ED51DA2AE09008EBF84 /* MasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MasterViewController.h; sourceTree = ""; }; + 53AA2ED61DA2AE09008EBF84 /* MasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MasterViewController.m; sourceTree = ""; }; + 53AA2ED81DA2AE09008EBF84 /* DetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; + 53AA2ED91DA2AE09008EBF84 /* DetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; + 53AA2EDC1DA2AE09008EBF84 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53AA2EDE1DA2AE09008EBF84 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53AA2EE11DA2AE09008EBF84 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53AA2EE31DA2AE09008EBF84 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53AA2EAF1DA2A957008EBF84 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53AA2ECA1DA2AE09008EBF84 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53AA2EA91DA2A957008EBF84 = { + isa = PBXGroup; + children = ( + 531225F81DA2E4440040CE8B /* README.md */, + 53AA2EB41DA2A957008EBF84 /* AllVisible */, + 53AA2ECE1DA2AE09008EBF84 /* AllVisibleObjC */, + 53AA2EB31DA2A957008EBF84 /* Products */, + ); + sourceTree = ""; + }; + 53AA2EB31DA2A957008EBF84 /* Products */ = { + isa = PBXGroup; + children = ( + 53AA2EB21DA2A957008EBF84 /* AllVisible.app */, + 53AA2ECD1DA2AE09008EBF84 /* AllVisibleObjC.app */, + ); + name = Products; + sourceTree = ""; + }; + 53AA2EB41DA2A957008EBF84 /* AllVisible */ = { + isa = PBXGroup; + children = ( + 53AA2EB51DA2A957008EBF84 /* AppDelegate.swift */, + 53AA2EB71DA2A957008EBF84 /* MasterViewController.swift */, + 53AA2EB91DA2A957008EBF84 /* DetailViewController.swift */, + 53AA2EBB1DA2A957008EBF84 /* Main.storyboard */, + 53AA2EBE1DA2A957008EBF84 /* Assets.xcassets */, + 53AA2EC01DA2A957008EBF84 /* LaunchScreen.storyboard */, + 53AA2EC31DA2A957008EBF84 /* Info.plist */, + ); + path = AllVisible; + sourceTree = ""; + }; + 53AA2ECE1DA2AE09008EBF84 /* AllVisibleObjC */ = { + isa = PBXGroup; + children = ( + 53AA2ED21DA2AE09008EBF84 /* AppDelegate.h */, + 53AA2ED31DA2AE09008EBF84 /* AppDelegate.m */, + 53AA2ED51DA2AE09008EBF84 /* MasterViewController.h */, + 53AA2ED61DA2AE09008EBF84 /* MasterViewController.m */, + 53AA2ED81DA2AE09008EBF84 /* DetailViewController.h */, + 53AA2ED91DA2AE09008EBF84 /* DetailViewController.m */, + 53AA2EDB1DA2AE09008EBF84 /* Main.storyboard */, + 53AA2EDE1DA2AE09008EBF84 /* Assets.xcassets */, + 53AA2EE01DA2AE09008EBF84 /* LaunchScreen.storyboard */, + 53AA2EE31DA2AE09008EBF84 /* Info.plist */, + 53AA2ECF1DA2AE09008EBF84 /* Supporting Files */, + ); + path = AllVisibleObjC; + sourceTree = ""; + }; + 53AA2ECF1DA2AE09008EBF84 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53AA2ED01DA2AE09008EBF84 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53AA2EB11DA2A957008EBF84 /* AllVisible */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53AA2EC61DA2A957008EBF84 /* Build configuration list for PBXNativeTarget "AllVisible" */; + buildPhases = ( + 53AA2EAE1DA2A957008EBF84 /* Sources */, + 53AA2EAF1DA2A957008EBF84 /* Frameworks */, + 53AA2EB01DA2A957008EBF84 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AllVisible; + productName = AllVisible; + productReference = 53AA2EB21DA2A957008EBF84 /* AllVisible.app */; + productType = "com.apple.product-type.application"; + }; + 53AA2ECC1DA2AE09008EBF84 /* AllVisibleObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53AA2EE41DA2AE09008EBF84 /* Build configuration list for PBXNativeTarget "AllVisibleObjC" */; + buildPhases = ( + 53AA2EC91DA2AE09008EBF84 /* Sources */, + 53AA2ECA1DA2AE09008EBF84 /* Frameworks */, + 53AA2ECB1DA2AE09008EBF84 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AllVisibleObjC; + productName = AllVisibleObjC; + productReference = 53AA2ECD1DA2AE09008EBF84 /* AllVisibleObjC.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53AA2EAA1DA2A957008EBF84 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0800; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53AA2EB11DA2A957008EBF84 = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + 53AA2ECC1DA2AE09008EBF84 = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53AA2EAD1DA2A957008EBF84 /* Build configuration list for PBXProject "AllVisible" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53AA2EA91DA2A957008EBF84; + productRefGroup = 53AA2EB31DA2A957008EBF84 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53AA2EB11DA2A957008EBF84 /* AllVisible */, + 53AA2ECC1DA2AE09008EBF84 /* AllVisibleObjC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53AA2EB01DA2A957008EBF84 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AA2EC21DA2A957008EBF84 /* LaunchScreen.storyboard in Resources */, + 53AA2EBF1DA2A957008EBF84 /* Assets.xcassets in Resources */, + 53AA2EBD1DA2A957008EBF84 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53AA2ECB1DA2AE09008EBF84 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AA2EE21DA2AE09008EBF84 /* LaunchScreen.storyboard in Resources */, + 53AA2EDF1DA2AE09008EBF84 /* Assets.xcassets in Resources */, + 53AA2EDD1DA2AE09008EBF84 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53AA2EAE1DA2A957008EBF84 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AA2EBA1DA2A957008EBF84 /* DetailViewController.swift in Sources */, + 53AA2EB81DA2A957008EBF84 /* MasterViewController.swift in Sources */, + 53AA2EB61DA2A957008EBF84 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53AA2EC91DA2AE09008EBF84 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AA2ED41DA2AE09008EBF84 /* AppDelegate.m in Sources */, + 53AA2ED71DA2AE09008EBF84 /* MasterViewController.m in Sources */, + 53AA2ED11DA2AE09008EBF84 /* main.m in Sources */, + 53AA2EDA1DA2AE09008EBF84 /* DetailViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53AA2EBB1DA2A957008EBF84 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AA2EBC1DA2A957008EBF84 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53AA2EC01DA2A957008EBF84 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AA2EC11DA2A957008EBF84 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 53AA2EDB1DA2AE09008EBF84 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AA2EDC1DA2AE09008EBF84 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53AA2EE01DA2AE09008EBF84 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AA2EE11DA2AE09008EBF84 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53AA2EC41DA2A957008EBF84 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53AA2EC51DA2A957008EBF84 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53AA2EC71DA2A957008EBF84 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AllVisible/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AllVisible; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53AA2EC81DA2A957008EBF84 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AllVisible/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AllVisible; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 53AA2EE51DA2AE09008EBF84 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AllVisibleObjC/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AllVisibleObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 53AA2EE61DA2AE09008EBF84 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AllVisibleObjC/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AllVisibleObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53AA2EAD1DA2A957008EBF84 /* Build configuration list for PBXProject "AllVisible" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53AA2EC41DA2A957008EBF84 /* Debug */, + 53AA2EC51DA2A957008EBF84 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53AA2EC61DA2A957008EBF84 /* Build configuration list for PBXNativeTarget "AllVisible" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53AA2EC71DA2A957008EBF84 /* Debug */, + 53AA2EC81DA2A957008EBF84 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53AA2EE41DA2AE09008EBF84 /* Build configuration list for PBXNativeTarget "AllVisibleObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53AA2EE51DA2AE09008EBF84 /* Debug */, + 53AA2EE61DA2AE09008EBF84 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53AA2EAA1DA2A957008EBF84 /* Project object */; +} diff --git a/AllVisible/AllVisible/AppDelegate.swift b/AllVisible/AllVisible/AppDelegate.swift new file mode 100644 index 0000000..c56dd48 --- /dev/null +++ b/AllVisible/AllVisible/AppDelegate.swift @@ -0,0 +1,69 @@ +// +// AppDelegate.swift +// AllVisible +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + guard let splitViewController = self.window?.rootViewController as? UISplitViewController else { + fatalError("Missing SplitViewController") + } + + guard let masterNavController = splitViewController.viewControllers.first as? UINavigationController, + let masterViewController = masterNavController.topViewController as? MasterViewController else { + fatalError("Missing MasterViewController") + } + + guard let navigationController = splitViewController.viewControllers.last as? UINavigationController, + let detailViewController = navigationController.topViewController else { + fatalError("Missing detail view controller") + } + + // Configure the SplitViewController to prefer to always + // show both master and detail views. + splitViewController.preferredDisplayMode = .allVisible + + // Make the master view controller the delegate. + splitViewController.delegate = masterViewController + + // Add the display mode button to the navigation bar + // of the secondary view controller. + detailViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem + detailViewController.navigationItem.leftItemsSupplementBackButton = true + + return true + } +} diff --git a/AllVisible/AllVisible/Assets.xcassets/AppIcon.appiconset/Contents.json b/AllVisible/AllVisible/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/AllVisible/AllVisible/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AllVisible/AllVisible/Base.lproj/LaunchScreen.storyboard b/AllVisible/AllVisible/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..323941e --- /dev/null +++ b/AllVisible/AllVisible/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AllVisible/AllVisible/Base.lproj/Main.storyboard b/AllVisible/AllVisible/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2723212 --- /dev/null +++ b/AllVisible/AllVisible/Base.lproj/Main.storyboard @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AllVisible/AllVisible/DetailViewController.swift b/AllVisible/AllVisible/DetailViewController.swift new file mode 100644 index 0000000..2bdf1ae --- /dev/null +++ b/AllVisible/AllVisible/DetailViewController.swift @@ -0,0 +1,55 @@ +// +// DetailViewController.swift +// AllVisible +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class DetailViewController: UIViewController { + @IBOutlet private var detailLabel: UILabel! + + private func configureView() { + if let label = detailLabel { + label.text = detailItem?.description + } + } + + override func viewDidLoad() { + super.viewDidLoad() + configureView() + } + + var detailItem: Date? { + didSet { + configureView() + } + } +} diff --git a/AllVisible/AllVisible/Info.plist b/AllVisible/AllVisible/Info.plist new file mode 100644 index 0000000..41f267e --- /dev/null +++ b/AllVisible/AllVisible/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AllVisible/AllVisible/MasterViewController.swift b/AllVisible/AllVisible/MasterViewController.swift new file mode 100644 index 0000000..6d1e170 --- /dev/null +++ b/AllVisible/AllVisible/MasterViewController.swift @@ -0,0 +1,65 @@ +// +// MasterViewController.swift +// AllVisible +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class MasterViewController: UIViewController { + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + guard let navController = segue.destination as? UINavigationController, + let viewController = navController.topViewController as? DetailViewController + else { + fatalError("Expected DetailViewController") + } + + viewController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem + viewController.navigationItem.leftItemsSupplementBackButton = true + viewController.detailItem = Date() + } +} + +extension MasterViewController: UISplitViewControllerDelegate { + func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { + // Returning true prevents the default of showing + // the secondary view controller. + guard let navigationController = secondaryViewController as? UINavigationController, + let detailViewController = navigationController.topViewController as? DetailViewController else { + // Fallback to the default + return false + } + + // Once we have something to show in the detail + // view return false to show the secondary in a + // collapsed split view + return detailViewController.detailItem == nil + } +} diff --git a/AllVisible/AllVisibleObjC/AppDelegate.h b/AllVisible/AllVisibleObjC/AppDelegate.h new file mode 100644 index 0000000..3ab1586 --- /dev/null +++ b/AllVisible/AllVisibleObjC/AppDelegate.h @@ -0,0 +1,43 @@ +// +// AppDelegate.h +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/AllVisible/AllVisibleObjC/AppDelegate.m b/AllVisible/AllVisibleObjC/AppDelegate.m new file mode 100644 index 0000000..a169974 --- /dev/null +++ b/AllVisible/AllVisibleObjC/AppDelegate.m @@ -0,0 +1,54 @@ +// +// AppDelegate.m +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" +#import "MasterViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; + splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; + + UINavigationController *masterNavigationController = [splitViewController.viewControllers firstObject]; + MasterViewController *masterViewController = (MasterViewController *)masterNavigationController.topViewController; + splitViewController.delegate = masterViewController; + + UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; + navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem; + navigationController.topViewController.navigationItem.leftItemsSupplementBackButton = YES; + return YES; +} + +@end diff --git a/AllVisible/AllVisibleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json b/AllVisible/AllVisibleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/AllVisible/AllVisibleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AllVisible/AllVisibleObjC/Base.lproj/LaunchScreen.storyboard b/AllVisible/AllVisibleObjC/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..b6ba895 --- /dev/null +++ b/AllVisible/AllVisibleObjC/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AllVisible/AllVisibleObjC/Base.lproj/Main.storyboard b/AllVisible/AllVisibleObjC/Base.lproj/Main.storyboard new file mode 100644 index 0000000..92f0fd7 --- /dev/null +++ b/AllVisible/AllVisibleObjC/Base.lproj/Main.storyboard @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AllVisible/AllVisibleObjC/DetailViewController.h b/AllVisible/AllVisibleObjC/DetailViewController.h new file mode 100644 index 0000000..7d2ab80 --- /dev/null +++ b/AllVisible/AllVisibleObjC/DetailViewController.h @@ -0,0 +1,39 @@ +// +// DetailViewController.h +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface DetailViewController : UIViewController +@property (copy, nonatomic, nullable) NSDate *detailItem; +@end diff --git a/AllVisible/AllVisibleObjC/DetailViewController.m b/AllVisible/AllVisibleObjC/DetailViewController.m new file mode 100644 index 0000000..7a041f6 --- /dev/null +++ b/AllVisible/AllVisibleObjC/DetailViewController.m @@ -0,0 +1,60 @@ +// +// DetailViewController.m +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "DetailViewController.h" + +@interface DetailViewController () +@property (weak, nonatomic) IBOutlet UILabel *detailLabel; +@end + +@implementation DetailViewController + +- (void)configureView { + if (self.detailItem) { + self.detailLabel.text = self.detailItem.description; + } +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [self configureView]; +} + +- (void)setDetailItem:(NSDate *)newDetailItem { + if (_detailItem != newDetailItem) { + _detailItem = newDetailItem; + [self configureView]; + } +} + +@end diff --git a/AllVisible/AllVisibleObjC/Info.plist b/AllVisible/AllVisibleObjC/Info.plist new file mode 100644 index 0000000..41f267e --- /dev/null +++ b/AllVisible/AllVisibleObjC/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AllVisible/AllVisibleObjC/MasterViewController.h b/AllVisible/AllVisibleObjC/MasterViewController.h new file mode 100644 index 0000000..0ed7dc7 --- /dev/null +++ b/AllVisible/AllVisibleObjC/MasterViewController.h @@ -0,0 +1,38 @@ +// +// MasterViewController.h +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface MasterViewController : UIViewController +@end diff --git a/AllVisible/AllVisibleObjC/MasterViewController.m b/AllVisible/AllVisibleObjC/MasterViewController.m new file mode 100644 index 0000000..f570cf8 --- /dev/null +++ b/AllVisible/AllVisibleObjC/MasterViewController.m @@ -0,0 +1,63 @@ +// +// MasterViewController.m +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "MasterViewController.h" +#import "DetailViewController.h" + +@implementation MasterViewController + +- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { + if ([secondaryViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *navigationController = (UINavigationController *)secondaryViewController; + if ([navigationController.topViewController isKindOfClass:[DetailViewController class]]) { + DetailViewController *detailViewController = (DetailViewController *)navigationController.topViewController; + return detailViewController.detailItem == NULL; + } + } + return NO; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([segue.destinationViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *navigationController = segue.destinationViewController; + if ([navigationController.topViewController isKindOfClass:[DetailViewController class]]) { + DetailViewController *viewController = (DetailViewController *)navigationController.topViewController; + viewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem; + viewController.navigationItem.leftItemsSupplementBackButton = YES; + viewController.detailItem = [NSDate date]; + } + } +} + +@end diff --git a/AllVisible/AllVisibleObjC/main.m b/AllVisible/AllVisibleObjC/main.m new file mode 100644 index 0000000..1e1c580 --- /dev/null +++ b/AllVisible/AllVisibleObjC/main.m @@ -0,0 +1,42 @@ +// +// main.m +// AllVisibleObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/AllVisible/README.md b/AllVisible/README.md new file mode 100644 index 0000000..c5ee204 --- /dev/null +++ b/AllVisible/README.md @@ -0,0 +1,5 @@ +### All Layout + +A simple Xcode project template showing how to configure a split view controller to prefer to show both the primary and secondary view controllers. Both Swift and Objective-C versions are included. + +For a more detailed explanation see [Split View Controller Display Modes](https://useyourloaf.com/blog/split-view-controller-display-modes/) diff --git a/AnimatedConstraints/AnimatedConstraints.xcodeproj/project.pbxproj b/AnimatedConstraints/AnimatedConstraints.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a579b76 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints.xcodeproj/project.pbxproj @@ -0,0 +1,330 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53D8FD6A1B08B9E100265E63 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D8FD691B08B9E100265E63 /* main.m */; }; + 53D8FD6D1B08B9E100265E63 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D8FD6C1B08B9E100265E63 /* AppDelegate.m */; }; + 53D8FD701B08B9E100265E63 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D8FD6F1B08B9E100265E63 /* ViewController.m */; }; + 53D8FD731B08B9E100265E63 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D8FD711B08B9E100265E63 /* Main.storyboard */; }; + 53D8FD751B08B9E100265E63 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53D8FD741B08B9E100265E63 /* Images.xcassets */; }; + 53D8FD931B08BF7000265E63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D8FD921B08BF7000265E63 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5326FC411B0A8FF5003FF69D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53D8FD641B08B9E100265E63 /* AnimatedConstraints.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnimatedConstraints.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53D8FD681B08B9E100265E63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53D8FD691B08B9E100265E63 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53D8FD6B1B08B9E100265E63 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 53D8FD6C1B08B9E100265E63 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 53D8FD6E1B08B9E100265E63 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 53D8FD6F1B08B9E100265E63 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 53D8FD721B08B9E100265E63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53D8FD741B08B9E100265E63 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53D8FD921B08BF7000265E63 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53D8FD611B08B9E100265E63 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53D8FD5B1B08B9E100265E63 = { + isa = PBXGroup; + children = ( + 5326FC411B0A8FF5003FF69D /* README.md */, + 53D8FD661B08B9E100265E63 /* AnimatedConstraints */, + 53D8FD651B08B9E100265E63 /* Products */, + ); + sourceTree = ""; + }; + 53D8FD651B08B9E100265E63 /* Products */ = { + isa = PBXGroup; + children = ( + 53D8FD641B08B9E100265E63 /* AnimatedConstraints.app */, + ); + name = Products; + sourceTree = ""; + }; + 53D8FD661B08B9E100265E63 /* AnimatedConstraints */ = { + isa = PBXGroup; + children = ( + 53D8FD6E1B08B9E100265E63 /* ViewController.h */, + 53D8FD6F1B08B9E100265E63 /* ViewController.m */, + 53D8FD711B08B9E100265E63 /* Main.storyboard */, + 53D8FD671B08B9E100265E63 /* Supporting Files */, + ); + path = AnimatedConstraints; + sourceTree = ""; + }; + 53D8FD671B08B9E100265E63 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53D8FD741B08B9E100265E63 /* Images.xcassets */, + 53D8FD6B1B08B9E100265E63 /* AppDelegate.h */, + 53D8FD6C1B08B9E100265E63 /* AppDelegate.m */, + 53D8FD681B08B9E100265E63 /* Info.plist */, + 53D8FD691B08B9E100265E63 /* main.m */, + 53D8FD921B08BF7000265E63 /* LaunchScreen.storyboard */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53D8FD631B08B9E100265E63 /* AnimatedConstraints */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53D8FD871B08B9E200265E63 /* Build configuration list for PBXNativeTarget "AnimatedConstraints" */; + buildPhases = ( + 53D8FD601B08B9E100265E63 /* Sources */, + 53D8FD611B08B9E100265E63 /* Frameworks */, + 53D8FD621B08B9E100265E63 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AnimatedConstraints; + productName = AnimatedConstraints; + productReference = 53D8FD641B08B9E100265E63 /* AnimatedConstraints.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53D8FD5C1B08B9E100265E63 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1110; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53D8FD631B08B9E100265E63 = { + CreatedOnToolsVersion = 6.3.1; + DevelopmentTeam = LCC2J94N44; + }; + }; + }; + buildConfigurationList = 53D8FD5F1B08B9E100265E63 /* Build configuration list for PBXProject "AnimatedConstraints" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53D8FD5B1B08B9E100265E63; + productRefGroup = 53D8FD651B08B9E100265E63 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53D8FD631B08B9E100265E63 /* AnimatedConstraints */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53D8FD621B08B9E100265E63 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53D8FD931B08BF7000265E63 /* LaunchScreen.storyboard in Resources */, + 53D8FD731B08B9E100265E63 /* Main.storyboard in Resources */, + 53D8FD751B08B9E100265E63 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53D8FD601B08B9E100265E63 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53D8FD701B08B9E100265E63 /* ViewController.m in Sources */, + 53D8FD6D1B08B9E100265E63 /* AppDelegate.m in Sources */, + 53D8FD6A1B08B9E100265E63 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53D8FD711B08B9E100265E63 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53D8FD721B08B9E100265E63 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53D8FD851B08B9E200265E63 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53D8FD861B08B9E200265E63 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53D8FD881B08B9E200265E63 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AnimatedConstraints/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 53D8FD891B08B9E200265E63 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 2; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AnimatedConstraints/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53D8FD5F1B08B9E100265E63 /* Build configuration list for PBXProject "AnimatedConstraints" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D8FD851B08B9E200265E63 /* Debug */, + 53D8FD861B08B9E200265E63 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53D8FD871B08B9E200265E63 /* Build configuration list for PBXNativeTarget "AnimatedConstraints" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D8FD881B08B9E200265E63 /* Debug */, + 53D8FD891B08B9E200265E63 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53D8FD5C1B08B9E100265E63 /* Project object */; +} diff --git a/AnimatedConstraints/AnimatedConstraints/AppDelegate.h b/AnimatedConstraints/AnimatedConstraints/AppDelegate.h new file mode 100644 index 0000000..2ad4638 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/AppDelegate.h @@ -0,0 +1,38 @@ +// +// AppDelegate.h +// AnimatedConstraints +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +@import UIKit; + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end \ No newline at end of file diff --git a/AnimatedConstraints/AnimatedConstraints/AppDelegate.m b/AnimatedConstraints/AnimatedConstraints/AppDelegate.m new file mode 100644 index 0000000..79fa8dd --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/AppDelegate.m @@ -0,0 +1,37 @@ +// +// AppDelegate.m +// AnimatedConstraints +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/AnimatedConstraints/AnimatedConstraints/Base.lproj/Main.storyboard b/AnimatedConstraints/AnimatedConstraints/Base.lproj/Main.storyboard new file mode 100644 index 0000000..ce347f7 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/Base.lproj/Main.storyboard @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/Contents.json b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..6fe8d1f --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-41.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-87.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x-1.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-180.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-42.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-167.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-1024.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000..4a1a9de Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-167.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-167.png new file mode 100644 index 0000000..0a5ec66 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-167.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-180.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-180.png new file mode 100644 index 0000000..fd2fbe9 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-180.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-20.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-20.png new file mode 100644 index 0000000..3c16adf Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-20.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000..b257b07 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000..95e7063 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-41.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-41.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-41.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-42.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-42.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-42.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60.png new file mode 100644 index 0000000..fd2eff6 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x-1.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x-1.png new file mode 100644 index 0000000..515d2b6 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x-1.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 0000000..515d2b6 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-60@2x.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000..89ca713 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76@2x.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000..7bdbed3 Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-87.png b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-87.png new file mode 100644 index 0000000..ec6564e Binary files /dev/null and b/AnimatedConstraints/AnimatedConstraints/Images.xcassets/AppIcon.appiconset/icon-87.png differ diff --git a/AnimatedConstraints/AnimatedConstraints/Info.plist b/AnimatedConstraints/AnimatedConstraints/Info.plist new file mode 100644 index 0000000..bd1ead3 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AnimatedConstraints/AnimatedConstraints/LaunchScreen.storyboard b/AnimatedConstraints/AnimatedConstraints/LaunchScreen.storyboard new file mode 100644 index 0000000..8d412a2 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/LaunchScreen.storyboard @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AnimatedConstraints/AnimatedConstraints/ViewController.h b/AnimatedConstraints/AnimatedConstraints/ViewController.h new file mode 100644 index 0000000..3de3174 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/ViewController.h @@ -0,0 +1,39 @@ +// +// ViewController.h +// AnimatedConstraints +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +@interface ViewController : UIViewController +@end + diff --git a/AnimatedConstraints/AnimatedConstraints/ViewController.m b/AnimatedConstraints/AnimatedConstraints/ViewController.m new file mode 100644 index 0000000..f1eea66 --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/ViewController.m @@ -0,0 +1,81 @@ +// +// ViewController.m +// AnimatedConstraints +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "ViewController.h" + +@interface ViewController () + +@property (weak, nonatomic) IBOutlet UISwitch *modeSwitch; +@property (weak, nonatomic) IBOutlet UIView *yellowView; +@property (weak, nonatomic) IBOutlet UIView *blueView; + +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *viewSpacingContraint; +@property (weak, nonatomic) IBOutlet NSLayoutConstraint *blueViewConstraint; + +@end + +@implementation ViewController + +NSString *modeUserDefaultKey = @"modeUserDefaultKey"; + +- (void)viewDidLoad { + [super viewDidLoad]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + self.modeSwitch.on = [defaults boolForKey:modeUserDefaultKey]; + [self updateConstraintsForMode]; +} + +- (IBAction)enableMode:(UISwitch *)sender { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:sender.isOn forKey:modeUserDefaultKey]; + [defaults synchronize]; + + [self.view layoutIfNeeded]; + [UIView animateWithDuration:1.0 animations:^{ + [self updateConstraintsForMode]; + [self.view layoutIfNeeded]; + }]; +} + +- (void)updateConstraintsForMode { + if (self.modeSwitch.isOn) { + self.viewSpacingContraint.constant = 8.0; + self.blueViewConstraint.priority = UILayoutPriorityDefaultHigh+1; + } else { + self.viewSpacingContraint.constant = self.view.frame.size.width; + self.blueViewConstraint.priority = UILayoutPriorityDefaultHigh-1; + } +} + +@end diff --git a/AnimatedConstraints/AnimatedConstraints/main.m b/AnimatedConstraints/AnimatedConstraints/main.m new file mode 100644 index 0000000..a80118c --- /dev/null +++ b/AnimatedConstraints/AnimatedConstraints/main.m @@ -0,0 +1,16 @@ +// +// main.m +// AnimatedConstraints +// +// Created by Keith Harrison on 17/05/2015. +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/AnimatedConstraints/README.md b/AnimatedConstraints/README.md new file mode 100644 index 0000000..cdbb29f --- /dev/null +++ b/AnimatedConstraints/README.md @@ -0,0 +1,16 @@ +# AnimatedConstraints + + +An example on how to animate changes made to autolayout constraints. +For further details see the post: + ++ [Animating Autolayout Constraints](https://useyourloaf.com/blog/animating-autolayout-constraints/) + +## Version History + ++ Version 1.2 - 04 Oct 2019 + Minor refresh for Xcode 11. ++ Version 1.1 - 21 May 2015 + Switch to changing priorities rather than adding/removing constraints. ++ Version 1.0 - 18 May 2015 + Initial Version diff --git a/AirPrinter/AirPrinter.xcodeproj/project.pbxproj b/Archive/AirPrinter/AirPrinter.xcodeproj/project.pbxproj similarity index 90% rename from AirPrinter/AirPrinter.xcodeproj/project.pbxproj rename to Archive/AirPrinter/AirPrinter.xcodeproj/project.pbxproj index 687d0f6..d1e10dd 100644 --- a/AirPrinter/AirPrinter.xcodeproj/project.pbxproj +++ b/Archive/AirPrinter/AirPrinter.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -29,6 +29,9 @@ 5310096E13E73E49008FC50D /* WebViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WebViewController.xib; sourceTree = ""; }; 5310097613E74913008FC50D /* UYLGenericPrintPageRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLGenericPrintPageRenderer.h; sourceTree = ""; }; 5310097713E74913008FC50D /* UYLGenericPrintPageRenderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLGenericPrintPageRenderer.m; sourceTree = ""; }; + 5334609623CA6FC800BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainWindow.xib; sourceTree = ""; }; + 5334609723CA6FC900BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/RootViewController.xib; sourceTree = ""; }; + 5334609823CA6FC900BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "iPad/Base.lproj/MainWindow-iPad.xib"; sourceTree = ""; }; 5336C32213E46620007FB510 /* AirPrinter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AirPrinter.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5336C32613E46620007FB510 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 5336C32813E46620007FB510 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -39,11 +42,8 @@ 5336C33413E46620007FB510 /* AirPrinter-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AirPrinter-Prefix.pch"; sourceTree = ""; }; 5336C33513E46620007FB510 /* AirPrinterAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AirPrinterAppDelegate.h; sourceTree = ""; }; 5336C33613E46620007FB510 /* AirPrinterAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AirPrinterAppDelegate.m; sourceTree = ""; }; - 5336C33913E46620007FB510 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; 5336C33B13E46620007FB510 /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; 5336C33C13E46620007FB510 /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; - 5336C33F13E46620007FB510 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/RootViewController.xib; sourceTree = ""; }; - 5336C34813E4663E007FB510 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = "iPad/en.lproj/MainWindow-iPad.xib"; sourceTree = ""; }; 53B8321B14069CB300E052A4 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -186,12 +186,16 @@ /* Begin PBXProject section */ 5336C31913E46620007FB510 /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + }; buildConfigurationList = 5336C31C13E46620007FB510 /* Build configuration list for PBXProject "AirPrinter" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 5336C31713E46620007FB510; productRefGroup = 5336C32313E46620007FB510 /* Products */; @@ -245,7 +249,7 @@ 5336C33813E46620007FB510 /* MainWindow.xib */ = { isa = PBXVariantGroup; children = ( - 5336C33913E46620007FB510 /* en */, + 5334609623CA6FC800BE943E /* Base */, ); name = MainWindow.xib; sourceTree = ""; @@ -253,7 +257,7 @@ 5336C33E13E46620007FB510 /* RootViewController.xib */ = { isa = PBXVariantGroup; children = ( - 5336C33F13E46620007FB510 /* en */, + 5334609723CA6FC900BE943E /* Base */, ); name = RootViewController.xib; sourceTree = ""; @@ -261,7 +265,7 @@ 5336C34713E4663E007FB510 /* MainWindow-iPad.xib */ = { isa = PBXVariantGroup; children = ( - 5336C34813E4663E007FB510 /* en */, + 5334609823CA6FC900BE943E /* Base */, ); name = "MainWindow-iPad.xib"; sourceTree = ""; @@ -273,9 +277,10 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -288,7 +293,8 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-DUYL_DEBUG"; SDKROOT = iphoneos; }; @@ -298,7 +304,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -306,7 +312,7 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -316,10 +322,14 @@ 5336C34413E46620007FB510 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + DEVELOPMENT_TEAM = LCC2J94N44; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "AirPrinter/AirPrinter-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = "AirPrinter/AirPrinter-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; @@ -329,10 +339,14 @@ 5336C34513E46620007FB510 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + DEVELOPMENT_TEAM = LCC2J94N44; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "AirPrinter/AirPrinter-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = "AirPrinter/AirPrinter-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; diff --git a/AirPrinter/AirPrinter/AirPrinter-Info.plist b/Archive/AirPrinter/AirPrinter/AirPrinter-Info.plist similarity index 94% rename from AirPrinter/AirPrinter/AirPrinter-Info.plist rename to Archive/AirPrinter/AirPrinter/AirPrinter-Info.plist index 3070946..cd79178 100644 --- a/AirPrinter/AirPrinter/AirPrinter-Info.plist +++ b/Archive/AirPrinter/AirPrinter/AirPrinter-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFile CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/AirPrinter/AirPrinter/AirPrinter-Prefix.pch b/Archive/AirPrinter/AirPrinter/AirPrinter-Prefix.pch similarity index 100% rename from AirPrinter/AirPrinter/AirPrinter-Prefix.pch rename to Archive/AirPrinter/AirPrinter/AirPrinter-Prefix.pch diff --git a/AirPrinter/AirPrinter/AirPrinterAppDelegate.h b/Archive/AirPrinter/AirPrinter/AirPrinterAppDelegate.h similarity index 100% rename from AirPrinter/AirPrinter/AirPrinterAppDelegate.h rename to Archive/AirPrinter/AirPrinter/AirPrinterAppDelegate.h diff --git a/AirPrinter/AirPrinter/AirPrinterAppDelegate.m b/Archive/AirPrinter/AirPrinter/AirPrinterAppDelegate.m similarity index 100% rename from AirPrinter/AirPrinter/AirPrinterAppDelegate.m rename to Archive/AirPrinter/AirPrinter/AirPrinterAppDelegate.m diff --git a/Archive/AirPrinter/AirPrinter/Base.lproj/MainWindow.xib b/Archive/AirPrinter/AirPrinter/Base.lproj/MainWindow.xib new file mode 100644 index 0000000..a6f7cfc --- /dev/null +++ b/Archive/AirPrinter/AirPrinter/Base.lproj/MainWindow.xib @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/AirPrinter/AirPrinter/Base.lproj/RootViewController.xib b/Archive/AirPrinter/AirPrinter/Base.lproj/RootViewController.xib new file mode 100644 index 0000000..ea17a5e --- /dev/null +++ b/Archive/AirPrinter/AirPrinter/Base.lproj/RootViewController.xib @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AirPrinter/AirPrinter/RootViewController.h b/Archive/AirPrinter/AirPrinter/RootViewController.h similarity index 100% rename from AirPrinter/AirPrinter/RootViewController.h rename to Archive/AirPrinter/AirPrinter/RootViewController.h diff --git a/AirPrinter/AirPrinter/RootViewController.m b/Archive/AirPrinter/AirPrinter/RootViewController.m similarity index 100% rename from AirPrinter/AirPrinter/RootViewController.m rename to Archive/AirPrinter/AirPrinter/RootViewController.m diff --git a/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.h b/Archive/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.h similarity index 100% rename from AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.h rename to Archive/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.h diff --git a/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.m b/Archive/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.m similarity index 100% rename from AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.m rename to Archive/AirPrinter/AirPrinter/UYLGenericPrintPageRenderer.m diff --git a/AirPrinter/AirPrinter/WebViewController.h b/Archive/AirPrinter/AirPrinter/WebViewController.h similarity index 100% rename from AirPrinter/AirPrinter/WebViewController.h rename to Archive/AirPrinter/AirPrinter/WebViewController.h diff --git a/AirPrinter/AirPrinter/WebViewController.m b/Archive/AirPrinter/AirPrinter/WebViewController.m similarity index 100% rename from AirPrinter/AirPrinter/WebViewController.m rename to Archive/AirPrinter/AirPrinter/WebViewController.m diff --git a/Archive/AirPrinter/AirPrinter/WebViewController.xib b/Archive/AirPrinter/AirPrinter/WebViewController.xib new file mode 100644 index 0000000..58e917e --- /dev/null +++ b/Archive/AirPrinter/AirPrinter/WebViewController.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AirPrinter/AirPrinter/en.lproj/InfoPlist.strings b/Archive/AirPrinter/AirPrinter/en.lproj/InfoPlist.strings similarity index 100% rename from AirPrinter/AirPrinter/en.lproj/InfoPlist.strings rename to Archive/AirPrinter/AirPrinter/en.lproj/InfoPlist.strings diff --git a/Archive/AirPrinter/AirPrinter/iPad/Base.lproj/MainWindow-iPad.xib b/Archive/AirPrinter/AirPrinter/iPad/Base.lproj/MainWindow-iPad.xib new file mode 100644 index 0000000..52816fd --- /dev/null +++ b/Archive/AirPrinter/AirPrinter/iPad/Base.lproj/MainWindow-iPad.xib @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AirPrinter/AirPrinter/main.m b/Archive/AirPrinter/AirPrinter/main.m similarity index 100% rename from AirPrinter/AirPrinter/main.m rename to Archive/AirPrinter/AirPrinter/main.m diff --git a/AlertView/AlertView.xcodeproj/project.pbxproj b/Archive/AlertView/AlertView.xcodeproj/project.pbxproj similarity index 80% rename from AlertView/AlertView.xcodeproj/project.pbxproj rename to Archive/AlertView/AlertView.xcodeproj/project.pbxproj index 3bef398..0af1f42 100644 --- a/AlertView/AlertView.xcodeproj/project.pbxproj +++ b/Archive/AlertView/AlertView.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5334609223CA652200BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLViewController.xib; sourceTree = ""; }; 534028B91497F89D002DB13A /* AlertView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlertView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 534028BD1497F89D002DB13A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 534028BF1497F89D002DB13A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -30,7 +31,6 @@ 534028CD1497F89D002DB13A /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; 534028CF1497F89D002DB13A /* UYLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; 534028D01497F89D002DB13A /* UYLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; - 534028D31497F89D002DB13A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLViewController.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,14 +124,15 @@ 534028B01497F89D002DB13A /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0420; + LastUpgradeCheck = 1120; }; buildConfigurationList = 534028B31497F89D002DB13A /* Build configuration list for PBXProject "AlertView" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 534028AE1497F89D002DB13A; productRefGroup = 534028BA1497F89D002DB13A /* Products */; @@ -180,7 +181,7 @@ 534028D21497F89D002DB13A /* UYLViewController.xib */ = { isa = PBXVariantGroup; children = ( - 534028D31497F89D002DB13A /* en */, + 5334609223CA652200BE943E /* Base */, ); name = UYLViewController.xib; sourceTree = ""; @@ -192,11 +193,31 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -204,10 +225,15 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -216,15 +242,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -234,9 +283,11 @@ 534028D81497F89D002DB13A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "AlertView/AlertView-Prefix.pch"; INFOPLIST_FILE = "AlertView/AlertView-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -245,9 +296,11 @@ 534028D91497F89D002DB13A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "AlertView/AlertView-Prefix.pch"; INFOPLIST_FILE = "AlertView/AlertView-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -272,6 +325,7 @@ 534028D91497F89D002DB13A /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/AlertView/AlertView/AlertView-Info.plist b/Archive/AlertView/AlertView/AlertView-Info.plist similarity index 94% rename from AlertView/AlertView/AlertView-Info.plist rename to Archive/AlertView/AlertView/AlertView-Info.plist index f5d7a12..5da589d 100644 --- a/AlertView/AlertView/AlertView-Info.plist +++ b/Archive/AlertView/AlertView/AlertView-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFiles CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/AlertView/AlertView/AlertView-Prefix.pch b/Archive/AlertView/AlertView/AlertView-Prefix.pch similarity index 100% rename from AlertView/AlertView/AlertView-Prefix.pch rename to Archive/AlertView/AlertView/AlertView-Prefix.pch diff --git a/Archive/AlertView/AlertView/Base.lproj/UYLViewController.xib b/Archive/AlertView/AlertView/Base.lproj/UYLViewController.xib new file mode 100644 index 0000000..154769b --- /dev/null +++ b/Archive/AlertView/AlertView/Base.lproj/UYLViewController.xib @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AlertView/AlertView/UYLAppDelegate.h b/Archive/AlertView/AlertView/UYLAppDelegate.h similarity index 100% rename from AlertView/AlertView/UYLAppDelegate.h rename to Archive/AlertView/AlertView/UYLAppDelegate.h diff --git a/AlertView/AlertView/UYLAppDelegate.m b/Archive/AlertView/AlertView/UYLAppDelegate.m similarity index 100% rename from AlertView/AlertView/UYLAppDelegate.m rename to Archive/AlertView/AlertView/UYLAppDelegate.m diff --git a/AlertView/AlertView/UYLViewController.h b/Archive/AlertView/AlertView/UYLViewController.h similarity index 100% rename from AlertView/AlertView/UYLViewController.h rename to Archive/AlertView/AlertView/UYLViewController.h diff --git a/AlertView/AlertView/UYLViewController.m b/Archive/AlertView/AlertView/UYLViewController.m similarity index 100% rename from AlertView/AlertView/UYLViewController.m rename to Archive/AlertView/AlertView/UYLViewController.m diff --git a/AlertView/AlertView/en.lproj/InfoPlist.strings b/Archive/AlertView/AlertView/en.lproj/InfoPlist.strings similarity index 100% rename from AlertView/AlertView/en.lproj/InfoPlist.strings rename to Archive/AlertView/AlertView/en.lproj/InfoPlist.strings diff --git a/AlertView/AlertView/main.m b/Archive/AlertView/AlertView/main.m similarity index 100% rename from AlertView/AlertView/main.m rename to Archive/AlertView/AlertView/main.m diff --git a/Archive/BUG TableView State Restore/README b/Archive/BUG TableView State Restore/README new file mode 100644 index 0000000..e463f6e --- /dev/null +++ b/Archive/BUG TableView State Restore/README @@ -0,0 +1,29 @@ +======================================================================= +Restore - State Preservation and Restoration of Table View + +Version 1.0 07 April 2013 Initial version. +======================================================================= + +This is a example project to reproduce a bug in the iOS 6 state preservation +and restoration code. The state of a table view is not restored when the table +is embedded in a navigation controller. + +The project contains two storyboards to demonstrate state restoration of a table +view both when it is the root view and when it is embedded in a navigation +controller: + +If the Target settings are used to set the Main Storyboad to NavStoryboard the +user inteface consists of UITableView embedded in a Navigation Controller. In +this use case the table view state is not restored. + +If the Target settings are used to set the Main Storyboard to MainStoryboard the +user interface consists of a single UITableView which does have state restored +as expected. + +For further details see the following blog post: + +https://useyourloaf.com/blog/bug-table-view-state-not-restored-when-embedded-in-navigation-controller/ + +************************************************************************** +*** This bug has been tested and reproduced for iOS 6.0 and iOS 6.1.3. *** +************************************************************************** diff --git a/Archive/BUG TableView State Restore/UYLTableViewController.h b/Archive/BUG TableView State Restore/UYLTableViewController.h new file mode 100644 index 0000000..07b18a7 --- /dev/null +++ b/Archive/BUG TableView State Restore/UYLTableViewController.h @@ -0,0 +1,13 @@ +// +// UYLTableViewController.h +// restore +// +// Created by Keith Harrison on 17/03/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import + +@interface UYLTableViewController : UITableViewController + +@end diff --git a/Archive/BUG TableView State Restore/UYLTableViewController.m b/Archive/BUG TableView State Restore/UYLTableViewController.m new file mode 100644 index 0000000..7bb9f55 --- /dev/null +++ b/Archive/BUG TableView State Restore/UYLTableViewController.m @@ -0,0 +1,92 @@ +// +// UYLTableViewController.m +// restore +// +// Created by Keith Harrison on 17/03/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import "UYLTableViewController.h" + +@interface UYLTableViewController () + +@end + +@implementation UYLTableViewController + +#pragma mark - +#pragma mark === UITableViewDataSource Delegate +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return 1000; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"BasicCell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; + cell.textLabel.text = [NSString stringWithFormat:@"Cell #%d",indexPath.row]; + return cell; +} + +#pragma mark - +#pragma mark === State Preservation === +#pragma mark - + +// The following two methods are the suggested workaround from Apple to +// forse the table view state to be restored when embedded in a +// navigation controller. The key is to force the table view to +// reload data when the state has been restored. + +//- (void) encodeRestorableStateWithCoder:(NSCoder *)coder +//{ +// // Save anything relevant for our role as the TableView's DataSource +// [super encodeRestorableStateWithCoder:coder]; +//} +// +//- (void) decodeRestorableStateWithCoder:(NSCoder *)coder +//{ +// [super decodeRestorableStateWithCoder:coder]; +// // Restore whatever we need as the TableView's DataSource, and then... +// [self.tableView reloadData]; +//} + + +// The following two methods are not strictly necessary in this simple example +// but you would normally want to implement any time the data displayed in the +// table view can change between saving and restoring the view. +// +// In this case we can also use this methods to force a reload of the table +// view data when restoring state. This is a workaround for a bug that causes +// the table view state to not be restored when embedded in a navigation controller. + +- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view +{ + NSString *identifier = nil; + if (indexPath && view) + { + identifier = [NSString stringWithFormat:@"%d",indexPath.row]; + } + return identifier; +} + +- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view +{ + NSIndexPath *indexPath = nil; + if (identifier && view) + { + NSInteger row = [identifier integerValue]; + indexPath = [NSIndexPath indexPathForRow:row inSection:0]; + } + + // Force a reload when table view is embedded in nav controller + // or scroll position is not restored. Uncomment following line + // to workaround bug. + // [self.tableView reloadData]; + + return indexPath; +} + +@end diff --git a/Archive/BUG TableView State Restore/restore.xcodeproj/project.pbxproj b/Archive/BUG TableView State Restore/restore.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f3bb7b1 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore.xcodeproj/project.pbxproj @@ -0,0 +1,355 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53370CC116F62D8D0090DFC5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53370CC016F62D8D0090DFC5 /* UIKit.framework */; }; + 53370CC316F62D8D0090DFC5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53370CC216F62D8D0090DFC5 /* Foundation.framework */; }; + 53370CC516F62D8D0090DFC5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53370CC416F62D8D0090DFC5 /* CoreGraphics.framework */; }; + 53370CCB16F62D8D0090DFC5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53370CC916F62D8D0090DFC5 /* InfoPlist.strings */; }; + 53370CCD16F62D8D0090DFC5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53370CCC16F62D8D0090DFC5 /* main.m */; }; + 53370CD116F62D8D0090DFC5 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53370CD016F62D8D0090DFC5 /* UYLAppDelegate.m */; }; + 53370CD316F62D8D0090DFC5 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 53370CD216F62D8D0090DFC5 /* Default.png */; }; + 53370CD516F62D8D0090DFC5 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53370CD416F62D8D0090DFC5 /* Default@2x.png */; }; + 53370CD716F62D8D0090DFC5 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53370CD616F62D8D0090DFC5 /* Default-568h@2x.png */; }; + 53370CDA16F62D8D0090DFC5 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53370CD816F62D8D0090DFC5 /* MainStoryboard.storyboard */; }; + 53370CE516F62FF70090DFC5 /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53370CE416F62FF70090DFC5 /* UYLTableViewController.m */; }; + 537C3B7617121F9100FA27ED /* README in Resources */ = {isa = PBXBuildFile; fileRef = 537C3B7517121F9100FA27ED /* README */; }; + 53CEC02916F678A3007FA441 /* NavStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53CEC02816F678A3007FA441 /* NavStoryboard.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5334608723CA275700BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainStoryboard.storyboard; sourceTree = ""; }; + 53370CBD16F62D8D0090DFC5 /* restore.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = restore.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53370CC016F62D8D0090DFC5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 53370CC216F62D8D0090DFC5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 53370CC416F62D8D0090DFC5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 53370CC816F62D8D0090DFC5 /* restore-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "restore-Info.plist"; sourceTree = ""; }; + 53370CCA16F62D8D0090DFC5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 53370CCC16F62D8D0090DFC5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53370CCE16F62D8D0090DFC5 /* restore-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "restore-Prefix.pch"; sourceTree = ""; }; + 53370CCF16F62D8D0090DFC5 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 53370CD016F62D8D0090DFC5 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 53370CD216F62D8D0090DFC5 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; + 53370CD416F62D8D0090DFC5 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; + 53370CD616F62D8D0090DFC5 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + 53370CE316F62FF70090DFC5 /* UYLTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UYLTableViewController.h; path = ../UYLTableViewController.h; sourceTree = ""; }; + 53370CE416F62FF70090DFC5 /* UYLTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UYLTableViewController.m; path = ../UYLTableViewController.m; sourceTree = ""; }; + 537C3B7517121F9100FA27ED /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + 53CEC02816F678A3007FA441 /* NavStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NavStoryboard.storyboard; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53370CBA16F62D8D0090DFC5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 53370CC116F62D8D0090DFC5 /* UIKit.framework in Frameworks */, + 53370CC316F62D8D0090DFC5 /* Foundation.framework in Frameworks */, + 53370CC516F62D8D0090DFC5 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53370CB416F62D8D0090DFC5 = { + isa = PBXGroup; + children = ( + 537C3B7517121F9100FA27ED /* README */, + 53370CC616F62D8D0090DFC5 /* restore */, + 53370CBF16F62D8D0090DFC5 /* Frameworks */, + 53370CBE16F62D8D0090DFC5 /* Products */, + ); + sourceTree = ""; + }; + 53370CBE16F62D8D0090DFC5 /* Products */ = { + isa = PBXGroup; + children = ( + 53370CBD16F62D8D0090DFC5 /* restore.app */, + ); + name = Products; + sourceTree = ""; + }; + 53370CBF16F62D8D0090DFC5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 53370CC016F62D8D0090DFC5 /* UIKit.framework */, + 53370CC216F62D8D0090DFC5 /* Foundation.framework */, + 53370CC416F62D8D0090DFC5 /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 53370CC616F62D8D0090DFC5 /* restore */ = { + isa = PBXGroup; + children = ( + 53370CE316F62FF70090DFC5 /* UYLTableViewController.h */, + 53370CE416F62FF70090DFC5 /* UYLTableViewController.m */, + 53370CCF16F62D8D0090DFC5 /* UYLAppDelegate.h */, + 53370CD016F62D8D0090DFC5 /* UYLAppDelegate.m */, + 53370CD816F62D8D0090DFC5 /* MainStoryboard.storyboard */, + 53CEC02816F678A3007FA441 /* NavStoryboard.storyboard */, + 53370CC716F62D8D0090DFC5 /* Supporting Files */, + ); + path = restore; + sourceTree = ""; + }; + 53370CC716F62D8D0090DFC5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53370CC816F62D8D0090DFC5 /* restore-Info.plist */, + 53370CC916F62D8D0090DFC5 /* InfoPlist.strings */, + 53370CCC16F62D8D0090DFC5 /* main.m */, + 53370CCE16F62D8D0090DFC5 /* restore-Prefix.pch */, + 53370CD216F62D8D0090DFC5 /* Default.png */, + 53370CD416F62D8D0090DFC5 /* Default@2x.png */, + 53370CD616F62D8D0090DFC5 /* Default-568h@2x.png */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53370CBC16F62D8D0090DFC5 /* restore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53370CE016F62D8D0090DFC5 /* Build configuration list for PBXNativeTarget "restore" */; + buildPhases = ( + 53370CB916F62D8D0090DFC5 /* Sources */, + 53370CBA16F62D8D0090DFC5 /* Frameworks */, + 53370CBB16F62D8D0090DFC5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = restore; + productName = restore; + productReference = 53370CBD16F62D8D0090DFC5 /* restore.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53370CB516F62D8D0090DFC5 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 53370CB816F62D8D0090DFC5 /* Build configuration list for PBXProject "restore" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53370CB416F62D8D0090DFC5; + productRefGroup = 53370CBE16F62D8D0090DFC5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53370CBC16F62D8D0090DFC5 /* restore */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53370CBB16F62D8D0090DFC5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53370CCB16F62D8D0090DFC5 /* InfoPlist.strings in Resources */, + 53370CD316F62D8D0090DFC5 /* Default.png in Resources */, + 53370CD516F62D8D0090DFC5 /* Default@2x.png in Resources */, + 53370CD716F62D8D0090DFC5 /* Default-568h@2x.png in Resources */, + 53370CDA16F62D8D0090DFC5 /* MainStoryboard.storyboard in Resources */, + 53CEC02916F678A3007FA441 /* NavStoryboard.storyboard in Resources */, + 537C3B7617121F9100FA27ED /* README in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53370CB916F62D8D0090DFC5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53370CCD16F62D8D0090DFC5 /* main.m in Sources */, + 53370CD116F62D8D0090DFC5 /* UYLAppDelegate.m in Sources */, + 53370CE516F62FF70090DFC5 /* UYLTableViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53370CC916F62D8D0090DFC5 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53370CCA16F62D8D0090DFC5 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 53370CD816F62D8D0090DFC5 /* MainStoryboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5334608723CA275700BE943E /* Base */, + ); + name = MainStoryboard.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53370CDE16F62D8D0090DFC5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 53370CDF16F62D8D0090DFC5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53370CE116F62D8D0090DFC5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "restore/restore-Prefix.pch"; + INFOPLIST_FILE = "restore/restore-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 53370CE216F62D8D0090DFC5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "restore/restore-Prefix.pch"; + INFOPLIST_FILE = "restore/restore-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53370CB816F62D8D0090DFC5 /* Build configuration list for PBXProject "restore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53370CDE16F62D8D0090DFC5 /* Debug */, + 53370CDF16F62D8D0090DFC5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53370CE016F62D8D0090DFC5 /* Build configuration list for PBXNativeTarget "restore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53370CE116F62D8D0090DFC5 /* Debug */, + 53370CE216F62D8D0090DFC5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53370CB516F62D8D0090DFC5 /* Project object */; +} diff --git a/Archive/BUG TableView State Restore/restore/Base.lproj/MainStoryboard.storyboard b/Archive/BUG TableView State Restore/restore/Base.lproj/MainStoryboard.storyboard new file mode 100644 index 0000000..39f83d9 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/Base.lproj/MainStoryboard.storyboard @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/BUG TableView State Restore/restore/Default-568h@2x.png b/Archive/BUG TableView State Restore/restore/Default-568h@2x.png new file mode 100644 index 0000000..0891b7a Binary files /dev/null and b/Archive/BUG TableView State Restore/restore/Default-568h@2x.png differ diff --git a/Archive/BUG TableView State Restore/restore/Default.png b/Archive/BUG TableView State Restore/restore/Default.png new file mode 100644 index 0000000..4c8ca6f Binary files /dev/null and b/Archive/BUG TableView State Restore/restore/Default.png differ diff --git a/Archive/BUG TableView State Restore/restore/Default@2x.png b/Archive/BUG TableView State Restore/restore/Default@2x.png new file mode 100644 index 0000000..35b84cf Binary files /dev/null and b/Archive/BUG TableView State Restore/restore/Default@2x.png differ diff --git a/Archive/BUG TableView State Restore/restore/NavStoryboard.storyboard b/Archive/BUG TableView State Restore/restore/NavStoryboard.storyboard new file mode 100644 index 0000000..65a6686 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/NavStoryboard.storyboard @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Archive/BUG TableView State Restore/restore/UYLAppDelegate.h b/Archive/BUG TableView State Restore/restore/UYLAppDelegate.h new file mode 100644 index 0000000..1468664 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/UYLAppDelegate.h @@ -0,0 +1,15 @@ +// +// UYLAppDelegate.h +// restore +// +// Created by Keith Harrison on 17/03/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Archive/BUG TableView State Restore/restore/UYLAppDelegate.m b/Archive/BUG TableView State Restore/restore/UYLAppDelegate.m new file mode 100644 index 0000000..c5c8324 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/UYLAppDelegate.m @@ -0,0 +1,28 @@ +// +// UYLAppDelegate.m +// restore +// +// Created by Keith Harrison on 17/03/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + return YES; +} + +- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder +{ + return YES; +} + +- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder +{ + return YES; +} + +@end diff --git a/MasterSlide/MasterSlide/en.lproj/InfoPlist.strings b/Archive/BUG TableView State Restore/restore/en.lproj/InfoPlist.strings similarity index 100% rename from MasterSlide/MasterSlide/en.lproj/InfoPlist.strings rename to Archive/BUG TableView State Restore/restore/en.lproj/InfoPlist.strings diff --git a/Archive/BUG TableView State Restore/restore/main.m b/Archive/BUG TableView State Restore/restore/main.m new file mode 100644 index 0000000..ddd2cef --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/main.m @@ -0,0 +1,18 @@ +// +// main.m +// restore +// +// Created by Keith Harrison on 17/03/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/Archive/BUG TableView State Restore/restore/restore-Info.plist b/Archive/BUG TableView State Restore/restore/restore-Info.plist new file mode 100644 index 0000000..36d8600 --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/restore-Info.plist @@ -0,0 +1,41 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + NavStoryboard + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/Archive/BUG TableView State Restore/restore/restore-Prefix.pch b/Archive/BUG TableView State Restore/restore/restore-Prefix.pch new file mode 100644 index 0000000..da86cae --- /dev/null +++ b/Archive/BUG TableView State Restore/restore/restore-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'restore' target in the 'restore' project +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Archive/Collection/Collection.xcodeproj/project.pbxproj b/Archive/Collection/Collection.xcodeproj/project.pbxproj new file mode 100644 index 0000000..84347c5 --- /dev/null +++ b/Archive/Collection/Collection.xcodeproj/project.pbxproj @@ -0,0 +1,528 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 53A5F89517E3BA57000DB6B5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F89417E3BA57000DB6B5 /* Foundation.framework */; }; + 53A5F89717E3BA57000DB6B5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F89617E3BA57000DB6B5 /* CoreGraphics.framework */; }; + 53A5F89917E3BA57000DB6B5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F89817E3BA57000DB6B5 /* UIKit.framework */; }; + 53A5F89F17E3BA57000DB6B5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53A5F89D17E3BA57000DB6B5 /* InfoPlist.strings */; }; + 53A5F8A117E3BA57000DB6B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8A017E3BA57000DB6B5 /* main.m */; }; + 53A5F8A517E3BA57000DB6B5 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8A417E3BA57000DB6B5 /* UYLAppDelegate.m */; }; + 53A5F8A817E3BA57000DB6B5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53A5F8A617E3BA57000DB6B5 /* Main.storyboard */; }; + 53A5F8AB17E3BA57000DB6B5 /* UYLCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8AA17E3BA57000DB6B5 /* UYLCollectionViewController.m */; }; + 53A5F8AD17E3BA57000DB6B5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53A5F8AC17E3BA57000DB6B5 /* Images.xcassets */; }; + 53A5F8B417E3BA57000DB6B5 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F8B317E3BA57000DB6B5 /* XCTest.framework */; }; + 53A5F8B517E3BA57000DB6B5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F89417E3BA57000DB6B5 /* Foundation.framework */; }; + 53A5F8B617E3BA57000DB6B5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A5F89817E3BA57000DB6B5 /* UIKit.framework */; }; + 53A5F8BE17E3BA57000DB6B5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53A5F8BC17E3BA57000DB6B5 /* InfoPlist.strings */; }; + 53A5F8C017E3BA57000DB6B5 /* CollectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8BF17E3BA57000DB6B5 /* CollectionTests.m */; }; + 53A5F8CB17E3BFFB000DB6B5 /* UYLSimpleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8CA17E3BFFB000DB6B5 /* UYLSimpleCell.m */; }; + 53A5F8CE17E3C692000DB6B5 /* UYLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A5F8CD17E3C692000DB6B5 /* UYLViewController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 53A5F8B717E3BA57000DB6B5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 53A5F88917E3BA57000DB6B5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 53A5F89017E3BA57000DB6B5; + remoteInfo = Collection; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 53A5F89117E3BA57000DB6B5 /* Collection.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Collection.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53A5F89417E3BA57000DB6B5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 53A5F89617E3BA57000DB6B5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 53A5F89817E3BA57000DB6B5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 53A5F89C17E3BA57000DB6B5 /* Collection-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Collection-Info.plist"; sourceTree = ""; }; + 53A5F89E17E3BA57000DB6B5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 53A5F8A017E3BA57000DB6B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53A5F8A217E3BA57000DB6B5 /* Collection-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Collection-Prefix.pch"; sourceTree = ""; }; + 53A5F8A317E3BA57000DB6B5 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 53A5F8A417E3BA57000DB6B5 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 53A5F8A717E3BA57000DB6B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53A5F8A917E3BA57000DB6B5 /* UYLCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLCollectionViewController.h; sourceTree = ""; }; + 53A5F8AA17E3BA57000DB6B5 /* UYLCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLCollectionViewController.m; sourceTree = ""; }; + 53A5F8AC17E3BA57000DB6B5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53A5F8B217E3BA57000DB6B5 /* CollectionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CollectionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 53A5F8B317E3BA57000DB6B5 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 53A5F8BB17E3BA57000DB6B5 /* CollectionTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CollectionTests-Info.plist"; sourceTree = ""; }; + 53A5F8BD17E3BA57000DB6B5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 53A5F8BF17E3BA57000DB6B5 /* CollectionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CollectionTests.m; sourceTree = ""; }; + 53A5F8C917E3BFFB000DB6B5 /* UYLSimpleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLSimpleCell.h; sourceTree = ""; }; + 53A5F8CA17E3BFFB000DB6B5 /* UYLSimpleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLSimpleCell.m; sourceTree = ""; }; + 53A5F8CC17E3C692000DB6B5 /* UYLViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; + 53A5F8CD17E3C692000DB6B5 /* UYLViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; + 53D5C7E617F62BD50077FB0D /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53A5F88E17E3BA57000DB6B5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F89717E3BA57000DB6B5 /* CoreGraphics.framework in Frameworks */, + 53A5F89917E3BA57000DB6B5 /* UIKit.framework in Frameworks */, + 53A5F89517E3BA57000DB6B5 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53A5F8AF17E3BA57000DB6B5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F8B417E3BA57000DB6B5 /* XCTest.framework in Frameworks */, + 53A5F8B617E3BA57000DB6B5 /* UIKit.framework in Frameworks */, + 53A5F8B517E3BA57000DB6B5 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53A5F88817E3BA57000DB6B5 = { + isa = PBXGroup; + children = ( + 53D5C7E617F62BD50077FB0D /* README */, + 53A5F89A17E3BA57000DB6B5 /* Collection */, + 53A5F8B917E3BA57000DB6B5 /* CollectionTests */, + 53A5F89317E3BA57000DB6B5 /* Frameworks */, + 53A5F89217E3BA57000DB6B5 /* Products */, + ); + sourceTree = ""; + }; + 53A5F89217E3BA57000DB6B5 /* Products */ = { + isa = PBXGroup; + children = ( + 53A5F89117E3BA57000DB6B5 /* Collection.app */, + 53A5F8B217E3BA57000DB6B5 /* CollectionTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 53A5F89317E3BA57000DB6B5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 53A5F89417E3BA57000DB6B5 /* Foundation.framework */, + 53A5F89617E3BA57000DB6B5 /* CoreGraphics.framework */, + 53A5F89817E3BA57000DB6B5 /* UIKit.framework */, + 53A5F8B317E3BA57000DB6B5 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 53A5F89A17E3BA57000DB6B5 /* Collection */ = { + isa = PBXGroup; + children = ( + 53A5F8A317E3BA57000DB6B5 /* UYLAppDelegate.h */, + 53A5F8A417E3BA57000DB6B5 /* UYLAppDelegate.m */, + 53A5F8A617E3BA57000DB6B5 /* Main.storyboard */, + 53A5F8CC17E3C692000DB6B5 /* UYLViewController.h */, + 53A5F8CD17E3C692000DB6B5 /* UYLViewController.m */, + 53A5F8C917E3BFFB000DB6B5 /* UYLSimpleCell.h */, + 53A5F8CA17E3BFFB000DB6B5 /* UYLSimpleCell.m */, + 53A5F8A917E3BA57000DB6B5 /* UYLCollectionViewController.h */, + 53A5F8AA17E3BA57000DB6B5 /* UYLCollectionViewController.m */, + 53A5F8AC17E3BA57000DB6B5 /* Images.xcassets */, + 53A5F89B17E3BA57000DB6B5 /* Supporting Files */, + ); + path = Collection; + sourceTree = ""; + }; + 53A5F89B17E3BA57000DB6B5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53A5F89C17E3BA57000DB6B5 /* Collection-Info.plist */, + 53A5F89D17E3BA57000DB6B5 /* InfoPlist.strings */, + 53A5F8A017E3BA57000DB6B5 /* main.m */, + 53A5F8A217E3BA57000DB6B5 /* Collection-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53A5F8B917E3BA57000DB6B5 /* CollectionTests */ = { + isa = PBXGroup; + children = ( + 53A5F8BF17E3BA57000DB6B5 /* CollectionTests.m */, + 53A5F8BA17E3BA57000DB6B5 /* Supporting Files */, + ); + path = CollectionTests; + sourceTree = ""; + }; + 53A5F8BA17E3BA57000DB6B5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53A5F8BB17E3BA57000DB6B5 /* CollectionTests-Info.plist */, + 53A5F8BC17E3BA57000DB6B5 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53A5F89017E3BA57000DB6B5 /* Collection */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53A5F8C317E3BA57000DB6B5 /* Build configuration list for PBXNativeTarget "Collection" */; + buildPhases = ( + 53A5F88D17E3BA57000DB6B5 /* Sources */, + 53A5F88E17E3BA57000DB6B5 /* Frameworks */, + 53A5F88F17E3BA57000DB6B5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Collection; + productName = Collection; + productReference = 53A5F89117E3BA57000DB6B5 /* Collection.app */; + productType = "com.apple.product-type.application"; + }; + 53A5F8B117E3BA57000DB6B5 /* CollectionTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53A5F8C617E3BA57000DB6B5 /* Build configuration list for PBXNativeTarget "CollectionTests" */; + buildPhases = ( + 53A5F8AE17E3BA57000DB6B5 /* Sources */, + 53A5F8AF17E3BA57000DB6B5 /* Frameworks */, + 53A5F8B017E3BA57000DB6B5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 53A5F8B817E3BA57000DB6B5 /* PBXTargetDependency */, + ); + name = CollectionTests; + productName = CollectionTests; + productReference = 53A5F8B217E3BA57000DB6B5 /* CollectionTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53A5F88917E3BA57000DB6B5 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53A5F89017E3BA57000DB6B5 = { + DevelopmentTeam = LCC2J94N44; + }; + 53A5F8B117E3BA57000DB6B5 = { + TestTargetID = 53A5F89017E3BA57000DB6B5; + }; + }; + }; + buildConfigurationList = 53A5F88C17E3BA57000DB6B5 /* Build configuration list for PBXProject "Collection" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53A5F88817E3BA57000DB6B5; + productRefGroup = 53A5F89217E3BA57000DB6B5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53A5F89017E3BA57000DB6B5 /* Collection */, + 53A5F8B117E3BA57000DB6B5 /* CollectionTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53A5F88F17E3BA57000DB6B5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F8AD17E3BA57000DB6B5 /* Images.xcassets in Resources */, + 53A5F89F17E3BA57000DB6B5 /* InfoPlist.strings in Resources */, + 53A5F8A817E3BA57000DB6B5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53A5F8B017E3BA57000DB6B5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F8BE17E3BA57000DB6B5 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53A5F88D17E3BA57000DB6B5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F8A117E3BA57000DB6B5 /* main.m in Sources */, + 53A5F8A517E3BA57000DB6B5 /* UYLAppDelegate.m in Sources */, + 53A5F8CB17E3BFFB000DB6B5 /* UYLSimpleCell.m in Sources */, + 53A5F8AB17E3BA57000DB6B5 /* UYLCollectionViewController.m in Sources */, + 53A5F8CE17E3C692000DB6B5 /* UYLViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53A5F8AE17E3BA57000DB6B5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A5F8C017E3BA57000DB6B5 /* CollectionTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 53A5F8B817E3BA57000DB6B5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 53A5F89017E3BA57000DB6B5 /* Collection */; + targetProxy = 53A5F8B717E3BA57000DB6B5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 53A5F89D17E3BA57000DB6B5 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53A5F89E17E3BA57000DB6B5 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 53A5F8A617E3BA57000DB6B5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53A5F8A717E3BA57000DB6B5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53A5F8BC17E3BA57000DB6B5 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53A5F8BD17E3BA57000DB6B5 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53A5F8C117E3BA57000DB6B5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 2; + }; + name = Debug; + }; + 53A5F8C217E3BA57000DB6B5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 2; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53A5F8C417E3BA57000DB6B5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Collection/Collection-Prefix.pch"; + INFOPLIST_FILE = "Collection/Collection-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 53A5F8C517E3BA57000DB6B5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Collection/Collection-Prefix.pch"; + INFOPLIST_FILE = "Collection/Collection-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 53A5F8C717E3BA57000DB6B5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Collection.app/Collection"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + "$(DEVELOPER_FRAMEWORKS_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Collection/Collection-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = "CollectionTests/CollectionTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Debug; + }; + 53A5F8C817E3BA57000DB6B5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Collection.app/Collection"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + "$(DEVELOPER_FRAMEWORKS_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Collection/Collection-Prefix.pch"; + INFOPLIST_FILE = "CollectionTests/CollectionTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53A5F88C17E3BA57000DB6B5 /* Build configuration list for PBXProject "Collection" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53A5F8C117E3BA57000DB6B5 /* Debug */, + 53A5F8C217E3BA57000DB6B5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53A5F8C317E3BA57000DB6B5 /* Build configuration list for PBXNativeTarget "Collection" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53A5F8C417E3BA57000DB6B5 /* Debug */, + 53A5F8C517E3BA57000DB6B5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53A5F8C617E3BA57000DB6B5 /* Build configuration list for PBXNativeTarget "CollectionTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53A5F8C717E3BA57000DB6B5 /* Debug */, + 53A5F8C817E3BA57000DB6B5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53A5F88917E3BA57000DB6B5 /* Project object */; +} diff --git a/Archive/Collection/Collection/Base.lproj/Main.storyboard b/Archive/Collection/Collection/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f255ba7 --- /dev/null +++ b/Archive/Collection/Collection/Base.lproj/Main.storyboard @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Archive/Collection/Collection/Collection-Info.plist b/Archive/Collection/Collection/Collection-Info.plist new file mode 100644 index 0000000..f1c66e4 --- /dev/null +++ b/Archive/Collection/Collection/Collection-Info.plist @@ -0,0 +1,41 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Archive/Collection/Collection/Collection-Prefix.pch b/Archive/Collection/Collection/Collection-Prefix.pch new file mode 100644 index 0000000..82a2bb4 --- /dev/null +++ b/Archive/Collection/Collection/Collection-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/Contents.json b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..8279c03 --- /dev/null +++ b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,64 @@ +{ + "images" : [ + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000..b257b07 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29@2x.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000..95e7063 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40@2x.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000..89ca713 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76@2x.png b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000..7bdbed3 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/Contents.json b/Archive/Collection/Collection/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Archive/Collection/Collection/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Contents.json b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..bc976a6 --- /dev/null +++ b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,40 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait~ipad.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape~ipad.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "Default-Portrait@2x~ipad.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "Default-Landscape@2x~ipad.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png new file mode 100644 index 0000000..534be4d Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png new file mode 100644 index 0000000..7325c1d Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png new file mode 100644 index 0000000..30876cb Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png differ diff --git a/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png new file mode 100644 index 0000000..e182808 Binary files /dev/null and b/Archive/Collection/Collection/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png differ diff --git a/Archive/Collection/Collection/UYLAppDelegate.h b/Archive/Collection/Collection/UYLAppDelegate.h new file mode 100644 index 0000000..7a6a4ae --- /dev/null +++ b/Archive/Collection/Collection/UYLAppDelegate.h @@ -0,0 +1,39 @@ +// +// UYLAppDelegate.h +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Archive/Collection/Collection/UYLAppDelegate.m b/Archive/Collection/Collection/UYLAppDelegate.m new file mode 100644 index 0000000..9398d93 --- /dev/null +++ b/Archive/Collection/Collection/UYLAppDelegate.m @@ -0,0 +1,44 @@ +// +// UYLAppDelegate.m +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + return YES; +} + + +@end diff --git a/Archive/Collection/Collection/UYLCollectionViewController.h b/Archive/Collection/Collection/UYLCollectionViewController.h new file mode 100644 index 0000000..2f910e6 --- /dev/null +++ b/Archive/Collection/Collection/UYLCollectionViewController.h @@ -0,0 +1,38 @@ +// +// UYLViewController.h +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLCollectionViewController : UICollectionViewController + +@end diff --git a/Archive/Collection/Collection/UYLCollectionViewController.m b/Archive/Collection/Collection/UYLCollectionViewController.m new file mode 100644 index 0000000..eddfe0b --- /dev/null +++ b/Archive/Collection/Collection/UYLCollectionViewController.m @@ -0,0 +1,124 @@ +// +// UYLViewController.m +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLCollectionViewController.h" +#import "UYLViewController.h" +#import "UYLSimpleCell.h" + +@interface UYLCollectionViewController () + +@property (nonatomic, strong) UIPopoverController *uylPopoverController; + +@end + +@implementation UYLCollectionViewController + +static NSString *UYLStoryboardViewControllerID = @"UYLViewController"; +static NSString *UYLSimpleCellID = @"UYLSimpleCell"; + +#pragma mark - +#pragma mark === UICollectionViewDataSource === +#pragma mark - + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return 100; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + UYLSimpleCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:UYLSimpleCellID forIndexPath:indexPath]; + cell.cellLabel.text = [NSString stringWithFormat:@"cell %d",indexPath.row]; + return cell; +} + +#pragma mark - +#pragma mark === Gesture Recognizer Action === +#pragma mark - + +- (IBAction)doubleTappedCell:(id)sender +{ + CGPoint tappedPoint = [sender locationInView:self.collectionView]; + NSIndexPath *tappedCellPath = [self.collectionView indexPathForItemAtPoint:tappedPoint]; + + if (tappedCellPath) + { + UYLSimpleCell *cell = (UYLSimpleCell *)[self.collectionView cellForItemAtIndexPath:tappedCellPath]; + [self.collectionView selectItemAtIndexPath:tappedCellPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; + + if (self.uylPopoverController == nil) + { + UYLViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:UYLStoryboardViewControllerID]; + self.uylPopoverController = [[UIPopoverController alloc] initWithContentViewController:viewController]; + self.uylPopoverController.delegate = self; + } + + [self.uylPopoverController presentPopoverFromRect:cell.frame + inView:self.collectionView + permittedArrowDirections:UIPopoverArrowDirectionAny + animated:YES]; + + } +} + +#pragma mark - +#pragma mark === UIPopoverControllerDelegate === +#pragma mark - + +- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view +{ + if (self.uylPopoverController == popoverController) + { + NSArray *selectedItems = self.collectionView.indexPathsForSelectedItems; + NSIndexPath *itemPath = (NSIndexPath *)[selectedItems lastObject]; + if (itemPath) + { + UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:itemPath]; + if (cell) + { + CGRect requiredRect = cell.frame; + *rect = requiredRect; + } + } + } +} + +- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController +{ + for (NSIndexPath *indexPath in self.collectionView.indexPathsForSelectedItems) + { + [self.collectionView deselectItemAtIndexPath:indexPath animated:YES]; + } +} + +@end diff --git a/Archive/Collection/Collection/UYLSimpleCell.h b/Archive/Collection/Collection/UYLSimpleCell.h new file mode 100644 index 0000000..7dc2973 --- /dev/null +++ b/Archive/Collection/Collection/UYLSimpleCell.h @@ -0,0 +1,40 @@ +// +// UYLSimpleCell.h +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLSimpleCell : UICollectionViewCell + +@property (nonatomic, weak) IBOutlet UILabel *cellLabel; + +@end diff --git a/Archive/Collection/Collection/UYLSimpleCell.m b/Archive/Collection/Collection/UYLSimpleCell.m new file mode 100644 index 0000000..4660dff --- /dev/null +++ b/Archive/Collection/Collection/UYLSimpleCell.m @@ -0,0 +1,51 @@ +// +// UYLSimpleCell.m +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLSimpleCell.h" + +@implementation UYLSimpleCell + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) + { + UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectZero]; + backgroundView.layer.borderColor = [[UIColor lightGrayColor] CGColor]; + backgroundView.layer.borderWidth = 2; + self.selectedBackgroundView = backgroundView; + } + return self; +} + +@end diff --git a/Archive/Collection/Collection/UYLViewController.h b/Archive/Collection/Collection/UYLViewController.h new file mode 100644 index 0000000..f774f70 --- /dev/null +++ b/Archive/Collection/Collection/UYLViewController.h @@ -0,0 +1,38 @@ +// +// UYLViewController.h +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLViewController : UIViewController + +@end diff --git a/Archive/Collection/Collection/UYLViewController.m b/Archive/Collection/Collection/UYLViewController.m new file mode 100644 index 0000000..da2ab3e --- /dev/null +++ b/Archive/Collection/Collection/UYLViewController.m @@ -0,0 +1,50 @@ +// +// UYLViewController.m +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLViewController.h" + +@interface UYLViewController () + +@property (weak, nonatomic) IBOutlet UILabel *contentLabel; + +@end + +@implementation UYLViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.contentLabel.text = @"Content"; +} + +@end diff --git a/StaticTable/StaticTable/en.lproj/InfoPlist.strings b/Archive/Collection/Collection/en.lproj/InfoPlist.strings similarity index 100% rename from StaticTable/StaticTable/en.lproj/InfoPlist.strings rename to Archive/Collection/Collection/en.lproj/InfoPlist.strings diff --git a/Archive/Collection/Collection/main.m b/Archive/Collection/Collection/main.m new file mode 100644 index 0000000..840edb6 --- /dev/null +++ b/Archive/Collection/Collection/main.m @@ -0,0 +1,43 @@ +// +// main.m +// Collection +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/Archive/Collection/CollectionTests/CollectionTests-Info.plist b/Archive/Collection/CollectionTests/CollectionTests-Info.plist new file mode 100644 index 0000000..169b6f7 --- /dev/null +++ b/Archive/Collection/CollectionTests/CollectionTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Archive/Collection/CollectionTests/CollectionTests.m b/Archive/Collection/CollectionTests/CollectionTests.m new file mode 100644 index 0000000..96f9b2c --- /dev/null +++ b/Archive/Collection/CollectionTests/CollectionTests.m @@ -0,0 +1,34 @@ +// +// CollectionTests.m +// CollectionTests +// +// Created by Keith Harrison on 13/09/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import + +@interface CollectionTests : XCTestCase + +@end + +@implementation CollectionTests + +- (void)setUp +{ + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample +{ + XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); +} + +@end diff --git a/Stepper/Stepper/en.lproj/InfoPlist.strings b/Archive/Collection/CollectionTests/en.lproj/InfoPlist.strings similarity index 100% rename from Stepper/Stepper/en.lproj/InfoPlist.strings rename to Archive/Collection/CollectionTests/en.lproj/InfoPlist.strings diff --git a/Archive/Collection/README b/Archive/Collection/README new file mode 100644 index 0000000..9975405 --- /dev/null +++ b/Archive/Collection/README @@ -0,0 +1,16 @@ +======================================================================= +Collection - A Simple Collection View + +Version 1.0 27 September 2013 Initial version. +======================================================================= + +**THIS BUG WAS RESOLVED IN iOS 9.3** + +This is a example project to reproduce a bug in the way that iOS 7 +repostions popovers when a view is rotated. + +For further details see the following blog post: + +https://useyourloaf.com/blog/uipopover-arrow-not-repositioned-correctly-on-rotation/ + +You can also view the bug report on Open Radar at https://openradar.appspot.com/14995477 diff --git a/MasterSlide/MasterSlide.xcodeproj/project.pbxproj b/Archive/MasterSlide/MasterSlide.xcodeproj/project.pbxproj similarity index 81% rename from MasterSlide/MasterSlide.xcodeproj/project.pbxproj rename to Archive/MasterSlide/MasterSlide.xcodeproj/project.pbxproj index 148bd98..8383db9 100644 --- a/MasterSlide/MasterSlide.xcodeproj/project.pbxproj +++ b/Archive/MasterSlide/MasterSlide.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -21,6 +21,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5334609323CA65EF00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLMasterViewController.xib; sourceTree = ""; }; + 5334609423CA65F000BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLDetailViewController.xib; sourceTree = ""; }; 53A7615E146C7E9600B4F8F6 /* masterslide.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = masterslide.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53A76162146C7E9600B4F8F6 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 53A76164146C7E9600B4F8F6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -35,8 +37,6 @@ 53A76175146C7E9600B4F8F6 /* UYLMasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLMasterViewController.m; sourceTree = ""; }; 53A76177146C7E9600B4F8F6 /* UYLDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLDetailViewController.h; sourceTree = ""; }; 53A76178146C7E9600B4F8F6 /* UYLDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLDetailViewController.m; sourceTree = ""; }; - 53A7617B146C7E9700B4F8F6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLMasterViewController.xib; sourceTree = ""; }; - 53A7617E146C7E9700B4F8F6 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLDetailViewController.xib; sourceTree = ""; }; 53FF8C18146F264400005E54 /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -151,14 +151,15 @@ 53A76155146C7E9600B4F8F6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0420; + LastUpgradeCheck = 1120; }; - buildConfigurationList = 53A76158146C7E9600B4F8F6 /* Build configuration list for PBXProject "masterslide" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + buildConfigurationList = 53A76158146C7E9600B4F8F6 /* Build configuration list for PBXProject "MasterSlide" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 53A76153146C7E9600B4F8F6; productRefGroup = 53A7615F146C7E9600B4F8F6 /* Products */; @@ -210,7 +211,7 @@ 53A7617A146C7E9700B4F8F6 /* UYLMasterViewController.xib */ = { isa = PBXVariantGroup; children = ( - 53A7617B146C7E9700B4F8F6 /* en */, + 5334609323CA65EF00BE943E /* Base */, ); name = UYLMasterViewController.xib; sourceTree = ""; @@ -218,7 +219,7 @@ 53A7617D146C7E9700B4F8F6 /* UYLDetailViewController.xib */ = { isa = PBXVariantGroup; children = ( - 53A7617E146C7E9700B4F8F6 /* en */, + 5334609423CA65F000BE943E /* Base */, ); name = UYLDetailViewController.xib; sourceTree = ""; @@ -230,11 +231,31 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -242,10 +263,15 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; }; @@ -255,15 +281,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; @@ -274,9 +323,11 @@ 53A76183146C7E9700B4F8F6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "masterslide/masterslide-Prefix.pch"; INFOPLIST_FILE = "masterslide/masterslide-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -285,9 +336,11 @@ 53A76184146C7E9700B4F8F6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "masterslide/masterslide-Prefix.pch"; INFOPLIST_FILE = "masterslide/masterslide-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -296,7 +349,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 53A76158146C7E9600B4F8F6 /* Build configuration list for PBXProject "masterslide" */ = { + 53A76158146C7E9600B4F8F6 /* Build configuration list for PBXProject "MasterSlide" */ = { isa = XCConfigurationList; buildConfigurations = ( 53A76180146C7E9700B4F8F6 /* Debug */, diff --git a/Archive/MasterSlide/MasterSlide/Base.lproj/UYLDetailViewController.xib b/Archive/MasterSlide/MasterSlide/Base.lproj/UYLDetailViewController.xib new file mode 100644 index 0000000..4f045c5 --- /dev/null +++ b/Archive/MasterSlide/MasterSlide/Base.lproj/UYLDetailViewController.xib @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/MasterSlide/MasterSlide/Base.lproj/UYLMasterViewController.xib b/Archive/MasterSlide/MasterSlide/Base.lproj/UYLMasterViewController.xib new file mode 100644 index 0000000..77a8e58 --- /dev/null +++ b/Archive/MasterSlide/MasterSlide/Base.lproj/UYLMasterViewController.xib @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/MasterSlide/MasterSlide/MainWindow.xib b/Archive/MasterSlide/MasterSlide/MainWindow.xib new file mode 100644 index 0000000..dc9f4e1 --- /dev/null +++ b/Archive/MasterSlide/MasterSlide/MainWindow.xib @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MasterSlide/MasterSlide/MasterSlide-Info.plist b/Archive/MasterSlide/MasterSlide/MasterSlide-Info.plist similarity index 95% rename from MasterSlide/MasterSlide/MasterSlide-Info.plist rename to Archive/MasterSlide/MasterSlide/MasterSlide-Info.plist index 410100c..7d691bc 100644 --- a/MasterSlide/MasterSlide/MasterSlide-Info.plist +++ b/Archive/MasterSlide/MasterSlide/MasterSlide-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFiles CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -26,6 +26,8 @@ 1.0 LSRequiresIPhoneOS + NSMainNibFile + MainWindow UIRequiredDeviceCapabilities armv7 @@ -43,7 +45,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSMainNibFile - MainWindow diff --git a/MasterSlide/MasterSlide/MasterSlide-Prefix.pch b/Archive/MasterSlide/MasterSlide/MasterSlide-Prefix.pch similarity index 100% rename from MasterSlide/MasterSlide/MasterSlide-Prefix.pch rename to Archive/MasterSlide/MasterSlide/MasterSlide-Prefix.pch diff --git a/MasterSlide/MasterSlide/UYLAppDelegate.h b/Archive/MasterSlide/MasterSlide/UYLAppDelegate.h similarity index 100% rename from MasterSlide/MasterSlide/UYLAppDelegate.h rename to Archive/MasterSlide/MasterSlide/UYLAppDelegate.h diff --git a/MasterSlide/MasterSlide/UYLAppDelegate.m b/Archive/MasterSlide/MasterSlide/UYLAppDelegate.m similarity index 100% rename from MasterSlide/MasterSlide/UYLAppDelegate.m rename to Archive/MasterSlide/MasterSlide/UYLAppDelegate.m diff --git a/MasterSlide/MasterSlide/UYLDetailViewController.h b/Archive/MasterSlide/MasterSlide/UYLDetailViewController.h similarity index 100% rename from MasterSlide/MasterSlide/UYLDetailViewController.h rename to Archive/MasterSlide/MasterSlide/UYLDetailViewController.h diff --git a/MasterSlide/MasterSlide/UYLDetailViewController.m b/Archive/MasterSlide/MasterSlide/UYLDetailViewController.m similarity index 100% rename from MasterSlide/MasterSlide/UYLDetailViewController.m rename to Archive/MasterSlide/MasterSlide/UYLDetailViewController.m diff --git a/MasterSlide/MasterSlide/UYLMasterViewController.h b/Archive/MasterSlide/MasterSlide/UYLMasterViewController.h similarity index 100% rename from MasterSlide/MasterSlide/UYLMasterViewController.h rename to Archive/MasterSlide/MasterSlide/UYLMasterViewController.h diff --git a/MasterSlide/MasterSlide/UYLMasterViewController.m b/Archive/MasterSlide/MasterSlide/UYLMasterViewController.m similarity index 100% rename from MasterSlide/MasterSlide/UYLMasterViewController.m rename to Archive/MasterSlide/MasterSlide/UYLMasterViewController.m diff --git a/Styles/Styles/en.lproj/InfoPlist.strings b/Archive/MasterSlide/MasterSlide/en.lproj/InfoPlist.strings similarity index 100% rename from Styles/Styles/en.lproj/InfoPlist.strings rename to Archive/MasterSlide/MasterSlide/en.lproj/InfoPlist.strings diff --git a/MasterSlide/MasterSlide/main.m b/Archive/MasterSlide/MasterSlide/main.m similarity index 100% rename from MasterSlide/MasterSlide/main.m rename to Archive/MasterSlide/MasterSlide/main.m diff --git a/Archive/RemindMe/Base.lproj/Localizable.strings b/Archive/RemindMe/Base.lproj/Localizable.strings new file mode 100644 index 0000000..5c8b12a --- /dev/null +++ b/Archive/RemindMe/Base.lproj/Localizable.strings @@ -0,0 +1,11 @@ +/* + Localizable.strings + RemindMe + + Created by Keith Harrison on 01/07/2016. + Copyright © 2016 Keith Harrison. All rights reserved. +*/ + +"AlertBody" = "Did you forget something?"; +"AlertAction" = "Show me"; +"OK" = "OK"; diff --git a/Archive/RemindMe/Base.lproj/Main.storyboard b/Archive/RemindMe/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d10e6fb --- /dev/null +++ b/Archive/RemindMe/Base.lproj/Main.storyboard @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/RemindMe/Classes/AppDelegate.h b/Archive/RemindMe/Classes/AppDelegate.h new file mode 100644 index 0000000..e3d4580 --- /dev/null +++ b/Archive/RemindMe/Classes/AppDelegate.h @@ -0,0 +1,40 @@ +// +// AppDelegate.h +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + + +@interface AppDelegate : UIResponder + +@property (nonatomic, strong) UIWindow *window; +@end + diff --git a/Archive/RemindMe/Classes/AppDelegate.m b/Archive/RemindMe/Classes/AppDelegate.m new file mode 100644 index 0000000..70fce0a --- /dev/null +++ b/Archive/RemindMe/Classes/AppDelegate.m @@ -0,0 +1,74 @@ +// +// AppDelegate.m +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" +#import "RemindMeViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [self registerForLocalNotifications]; + UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; + if (notification) + { + [self handleNotification:notification]; + } + application.applicationIconBadgeNumber = 0; + return YES; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + application.applicationIconBadgeNumber = 0; +} + +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { + application.applicationIconBadgeNumber = 0; + [self handleNotification:notification]; +} + +- (void)registerForLocalNotifications +{ + UIUserNotificationSettings *settings = [UIUserNotificationSettings + settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound + categories:nil]; + [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; +} + +- (void)handleNotification:(UILocalNotification *)notification { + if ([self.window.rootViewController isKindOfClass:[RemindMeViewController class]]) { + RemindMeViewController *rootController = (RemindMeViewController *)self.window.rootViewController; + [rootController showReminder:notification]; + } +} + +@end diff --git a/Archive/RemindMe/Classes/RemindMeViewController.h b/Archive/RemindMe/Classes/RemindMeViewController.h new file mode 100644 index 0000000..a3deceb --- /dev/null +++ b/Archive/RemindMe/Classes/RemindMeViewController.h @@ -0,0 +1,37 @@ +// +// RemindMeViewController.h +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface RemindMeViewController : UIViewController +- (void)showReminder:(UILocalNotification *)notification; +@end diff --git a/Archive/RemindMe/Classes/RemindMeViewController.m b/Archive/RemindMe/Classes/RemindMeViewController.m new file mode 100644 index 0000000..91667bd --- /dev/null +++ b/Archive/RemindMe/Classes/RemindMeViewController.m @@ -0,0 +1,112 @@ +// +// RemindMeViewController.m +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "RemindMeViewController.h" + +@interface RemindMeViewController () +@property (nonatomic,strong) IBOutlet UITextField *reminderText; +@property (nonatomic,strong) IBOutlet UISegmentedControl *scheduleControl; +@property (nonatomic,strong) IBOutlet UIButton *setButton; +@property (nonatomic,strong) IBOutlet UIButton *clearButton; +@property (nonatomic,strong) IBOutlet UIDatePicker *datePicker; +@end + +@implementation RemindMeViewController + +NSString *kRemindMeNotificationDataKey = @"kRemindMeNotificationDataKey"; + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.datePicker.minimumDate = [NSDate date]; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + [textField resignFirstResponder]; + return YES; +} + +- (IBAction)clearNotification { + [[UIApplication sharedApplication] cancelAllLocalNotifications]; +} + +- (IBAction)scheduleNotification { + [self.reminderText resignFirstResponder]; + [[UIApplication sharedApplication] cancelAllLocalNotifications]; + + UILocalNotification *notif = [[UILocalNotification alloc] init]; + notif.fireDate = [self.datePicker date]; + notif.timeZone = [NSTimeZone defaultTimeZone]; + + notif.alertBody = NSLocalizedString(@"AlertBody",@"Did you forget something?"); + notif.alertAction = NSLocalizedString(@"AlertAction",@"Show me"); + notif.soundName = UILocalNotificationDefaultSoundName; + notif.applicationIconBadgeNumber = 1; + + NSInteger index = [self.scheduleControl selectedSegmentIndex]; + switch (index) + { + case 1: + notif.repeatInterval = NSCalendarUnitMinute; + break; + case 2: + notif.repeatInterval = NSCalendarUnitHour; + break; + case 3: + notif.repeatInterval = NSCalendarUnitDay; + break; + case 4: + notif.repeatInterval = NSCalendarUnitMonth; + break; + default: + notif.repeatInterval = 0; + break; + } + + NSDictionary *userDict = [NSDictionary dictionaryWithObject:self.reminderText.text + forKey:kRemindMeNotificationDataKey]; + notif.userInfo = userDict; + [[UIApplication sharedApplication] scheduleLocalNotification:notif]; +} + +- (void)showReminder:(UILocalNotification *)notification { + NSString *reminderText = [notification.userInfo objectForKey:kRemindMeNotificationDataKey]; + if (reminderText) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Reminder" message:reminderText preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK",@"OK") style:UIAlertActionStyleDefault handler:nil]; + [alertController addAction:okAction]; + [self presentViewController:alertController animated:YES completion:nil]; + } +} + +@end diff --git a/Archive/RemindMe/Info.plist b/Archive/RemindMe/Info.plist new file mode 100644 index 0000000..590ea48 --- /dev/null +++ b/Archive/RemindMe/Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 10 + LSApplicationCategoryType + + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Archive/RemindMe/LaunchScreen.storyboard b/Archive/RemindMe/LaunchScreen.storyboard new file mode 100644 index 0000000..d949f42 --- /dev/null +++ b/Archive/RemindMe/LaunchScreen.storyboard @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/RemindMe/README.md b/Archive/RemindMe/README.md new file mode 100644 index 0000000..fe0054d --- /dev/null +++ b/Archive/RemindMe/README.md @@ -0,0 +1,12 @@ +### RemindMe + +Version 1.2 01 Jul 2016 Update to Xcode 8 and iOS 10 +Version 1.1 06 Sep 2012 Minor updates to remove iOS 3 support +Version 1.0 31 Jul 2010 Initial release + +The RemindMe App is a demonstration on how to schedule local notifications using UILocalNotification. + +The original posts were written for iOS 4 a long time ago: + ++ [Repeating an iOS local notification](https://useyourloaf.com/blog/repeating-an-ios-local-notification/) ++ [Add Local Notification with iOS 4](https://useyourloaf.com/blog/adding-local-notifications-with-ios-4/) diff --git a/RemindMe/RemindMe.xcodeproj/project.pbxproj b/Archive/RemindMe/RemindMe.xcodeproj/project.pbxproj similarity index 53% rename from RemindMe/RemindMe.xcodeproj/project.pbxproj rename to Archive/RemindMe/RemindMe.xcodeproj/project.pbxproj index a90d7c2..f12800f 100755 --- a/RemindMe/RemindMe.xcodeproj/project.pbxproj +++ b/Archive/RemindMe/RemindMe.xcodeproj/project.pbxproj @@ -3,34 +3,31 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ - 1D3623260D0F684500981E51 /* RemindMeAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* RemindMeAppDelegate.m */; }; + 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; }; 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; - 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; - 2899E5220DE3E06400AC0155 /* RemindMeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* RemindMeViewController.xib */; }; - 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 28D7ACF80DDB3853001CB0EB /* RemindMeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* RemindMeViewController.m */; }; + 534536F21D2706BC00B3C4CC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 534536F11D2706BC00B3C4CC /* Images.xcassets */; }; + 534536F61D270C3800B3C4CC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 534536F51D270C3800B3C4CC /* LaunchScreen.storyboard */; }; + 5345371A1D272BFA00B3C4CC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5345371C1D272BFA00B3C4CC /* Main.storyboard */; }; + 534537201D272CB800B3C4CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 534537221D272CB800B3C4CC /* Localizable.strings */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1D3623240D0F684500981E51 /* RemindMeAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemindMeAppDelegate.h; sourceTree = ""; }; - 1D3623250D0F684500981E51 /* RemindMeAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemindMeAppDelegate.m; sourceTree = ""; }; + 1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 1D6058910D05DD3D006BFB54 /* RemindMe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RemindMe.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 2899E5210DE3E06400AC0155 /* RemindMeViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RemindMeViewController.xib; sourceTree = ""; }; - 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 28D7ACF60DDB3853001CB0EB /* RemindMeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemindMeViewController.h; sourceTree = ""; }; 28D7ACF70DDB3853001CB0EB /* RemindMeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemindMeViewController.m; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 32CA4F630368D1EE00C91783 /* RemindMe_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemindMe_Prefix.pch; sourceTree = ""; }; - 5350CE8315F8FB8700D7B1F3 /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; + 534536F11D2706BC00B3C4CC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = RemindMe/Images.xcassets; sourceTree = ""; }; + 534536F51D270C3800B3C4CC /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5345371D1D272C0C00B3C4CC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 534537211D272CB800B3C4CC /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + 5350CE8315F8FB8700D7B1F3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -39,9 +36,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, - 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, - 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -51,8 +45,8 @@ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( - 1D3623240D0F684500981E51 /* RemindMeAppDelegate.h */, - 1D3623250D0F684500981E51 /* RemindMeAppDelegate.m */, + 1D3623240D0F684500981E51 /* AppDelegate.h */, + 1D3623250D0F684500981E51 /* AppDelegate.m */, 28D7ACF60DDB3853001CB0EB /* RemindMeViewController.h */, 28D7ACF70DDB3853001CB0EB /* RemindMeViewController.m */, ); @@ -70,11 +64,10 @@ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( - 5350CE8315F8FB8700D7B1F3 /* README */, + 5350CE8315F8FB8700D7B1F3 /* README.md */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = CustomTemplate; @@ -83,7 +76,6 @@ 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( - 32CA4F630368D1EE00C91783 /* RemindMe_Prefix.pch */, 29B97316FDCFA39411CA2CEA /* main.m */, ); name = "Other Sources"; @@ -92,23 +84,15 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( - 2899E5210DE3E06400AC0155 /* RemindMeViewController.xib */, - 28AD733E0D9D9553002E5188 /* MainWindow.xib */, + 534536F11D2706BC00B3C4CC /* Images.xcassets */, 8D1107310486CEB800E47090 /* Info.plist */, + 5345371C1D272BFA00B3C4CC /* Main.storyboard */, + 534536F51D270C3800B3C4CC /* LaunchScreen.storyboard */, + 534537221D272CB800B3C4CC /* Localizable.strings */, ); name = Resources; sourceTree = ""; }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, - 1D30AB110D05D00D00671497 /* Foundation.framework */, - 288765A40DF7441C002DB57D /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -135,17 +119,22 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 1D6058900D05DD3D006BFB54 = { + DevelopmentTeam = LCC2J94N44; + DevelopmentTeamName = "Keith Harrison"; + }; + }; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "RemindMe" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 1; knownRegions = ( - English, - Japanese, - French, - German, + Base, + en, ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; projectDirPath = ""; @@ -161,8 +150,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, - 2899E5220DE3E06400AC0155 /* RemindMeViewController.xib in Resources */, + 534537201D272CB800B3C4CC /* Localizable.strings in Resources */, + 534536F21D2706BC00B3C4CC /* Images.xcassets in Resources */, + 534536F61D270C3800B3C4CC /* LaunchScreen.storyboard in Resources */, + 5345371A1D272BFA00B3C4CC /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -174,27 +165,49 @@ buildActionMask = 2147483647; files = ( 1D60589B0D05DD56006BFB54 /* main.m in Sources */, - 1D3623260D0F684500981E51 /* RemindMeAppDelegate.m in Sources */, + 1D3623260D0F684500981E51 /* AppDelegate.m in Sources */, 28D7ACF80DDB3853001CB0EB /* RemindMeViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXVariantGroup section */ + 5345371C1D272BFA00B3C4CC /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5345371D1D272C0C00B3C4CC /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 534537221D272CB800B3C4CC /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 534537211D272CB800B3C4CC /* Base */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 1D6058940D05DD3E006BFB54 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = RemindMe_Prefix.pch; INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 4.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMe; PRODUCT_NAME = RemindMe; SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -202,13 +215,16 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = RemindMe_Prefix.pch; INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 4.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMe; PRODUCT_NAME = RemindMe; SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -216,12 +232,39 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -229,12 +272,37 @@ C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; }; diff --git a/Archive/RemindMe/RemindMe/Images.xcassets/AppIcon.appiconset/Contents.json b/Archive/RemindMe/RemindMe/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/Archive/RemindMe/RemindMe/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/RemindMe/RemindMe/Images.xcassets/Contents.json b/Archive/RemindMe/RemindMe/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Archive/RemindMe/RemindMe/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/RemindMe/main.m b/Archive/RemindMe/main.m new file mode 100644 index 0000000..d26f1b8 --- /dev/null +++ b/Archive/RemindMe/main.m @@ -0,0 +1,41 @@ +// +// main.m +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/StaticTable/README.markdown b/Archive/StaticTable/README.markdown similarity index 100% rename from StaticTable/README.markdown rename to Archive/StaticTable/README.markdown diff --git a/StaticTable/StaticTable.xcodeproj/project.pbxproj b/Archive/StaticTable/StaticTable.xcodeproj/project.pbxproj similarity index 87% rename from StaticTable/StaticTable.xcodeproj/project.pbxproj rename to Archive/StaticTable/StaticTable.xcodeproj/project.pbxproj index bb3438f..e8d0a88 100644 --- a/StaticTable/StaticTable.xcodeproj/project.pbxproj +++ b/Archive/StaticTable/StaticTable.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -42,7 +42,7 @@ 532B11F7154F362C004B4780 /* second.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = second.png; sourceTree = ""; }; 532B11F9154F362C004B4780 /* second@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "second@2x.png"; sourceTree = ""; }; 532B1206154F3712004B4780 /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; - 53ACC43215582581005E26DC /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; path = README.markdown; sourceTree = ""; }; + 53ACC43215582581005E26DC /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; 53F33DE215508DBE0094277E /* UYLGeneralSettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLGeneralSettingsTableViewController.h; sourceTree = ""; }; 53F33DE315508DBE0094277E /* UYLGeneralSettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLGeneralSettingsTableViewController.m; sourceTree = ""; }; 53F33DE915509B360094277E /* UYLAdvancedSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLAdvancedSettingsViewController.h; sourceTree = ""; }; @@ -190,14 +190,15 @@ isa = PBXProject; attributes = { CLASSPREFIX = UYL; - LastUpgradeCheck = 0430; + LastUpgradeCheck = 1120; }; buildConfigurationList = 532B11D1154F362C004B4780 /* Build configuration list for PBXProject "StaticTable" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 532B11CC154F362C004B4780; productRefGroup = 532B11D8154F362C004B4780 /* Products */; @@ -259,12 +260,32 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -272,10 +293,14 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -284,16 +309,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -306,6 +353,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "StaticTable/StaticTable-Prefix.pch"; INFOPLIST_FILE = "StaticTable/StaticTable-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -317,6 +365,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "StaticTable/StaticTable-Prefix.pch"; INFOPLIST_FILE = "StaticTable/StaticTable-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/StaticTable/StaticTable/Settings.storyboard b/Archive/StaticTable/StaticTable/Settings.storyboard similarity index 70% rename from StaticTable/StaticTable/Settings.storyboard rename to Archive/StaticTable/StaticTable/Settings.storyboard index 9a8474f..bd38de0 100644 --- a/StaticTable/StaticTable/Settings.storyboard +++ b/Archive/StaticTable/StaticTable/Settings.storyboard @@ -1,140 +1,136 @@ - - + + + - - - + + + - + - - - + + - + - - + + - - + + - - - + - + - - + + - - + + - - - + - + - - + + - - + + - - - + - + - - + + - - + + - - - + @@ -154,132 +150,126 @@ + - + - + - - - + + - + - - + + - - - + - + - - + + - - - + - + - - + + - - - + - + - - + + - - - + - + - - + + - - - + - + - - + + - - - + @@ -291,17 +281,17 @@ + - + - - + @@ -309,38 +299,37 @@ + - + - + - - - + + - + - - + + - - - + @@ -350,22 +339,21 @@ - + - - + + - - - + @@ -380,34 +368,9 @@ + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/StaticTable/StaticTable/StaticTable-Info.plist b/Archive/StaticTable/StaticTable/StaticTable-Info.plist similarity index 94% rename from StaticTable/StaticTable/StaticTable-Info.plist rename to Archive/StaticTable/StaticTable/StaticTable-Info.plist index 408dd6d..9989d33 100644 --- a/StaticTable/StaticTable/StaticTable-Info.plist +++ b/Archive/StaticTable/StaticTable/StaticTable-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/StaticTable/StaticTable/StaticTable-Prefix.pch b/Archive/StaticTable/StaticTable/StaticTable-Prefix.pch similarity index 100% rename from StaticTable/StaticTable/StaticTable-Prefix.pch rename to Archive/StaticTable/StaticTable/StaticTable-Prefix.pch diff --git a/StaticTable/StaticTable/UYLAdvancedSettingsViewController.h b/Archive/StaticTable/StaticTable/UYLAdvancedSettingsViewController.h similarity index 100% rename from StaticTable/StaticTable/UYLAdvancedSettingsViewController.h rename to Archive/StaticTable/StaticTable/UYLAdvancedSettingsViewController.h diff --git a/StaticTable/StaticTable/UYLAdvancedSettingsViewController.m b/Archive/StaticTable/StaticTable/UYLAdvancedSettingsViewController.m similarity index 100% rename from StaticTable/StaticTable/UYLAdvancedSettingsViewController.m rename to Archive/StaticTable/StaticTable/UYLAdvancedSettingsViewController.m diff --git a/StaticTable/StaticTable/UYLAppDelegate.h b/Archive/StaticTable/StaticTable/UYLAppDelegate.h similarity index 100% rename from StaticTable/StaticTable/UYLAppDelegate.h rename to Archive/StaticTable/StaticTable/UYLAppDelegate.h diff --git a/StaticTable/StaticTable/UYLAppDelegate.m b/Archive/StaticTable/StaticTable/UYLAppDelegate.m similarity index 100% rename from StaticTable/StaticTable/UYLAppDelegate.m rename to Archive/StaticTable/StaticTable/UYLAppDelegate.m diff --git a/StaticTable/StaticTable/UYLFirstViewController.h b/Archive/StaticTable/StaticTable/UYLFirstViewController.h similarity index 100% rename from StaticTable/StaticTable/UYLFirstViewController.h rename to Archive/StaticTable/StaticTable/UYLFirstViewController.h diff --git a/StaticTable/StaticTable/UYLFirstViewController.m b/Archive/StaticTable/StaticTable/UYLFirstViewController.m similarity index 100% rename from StaticTable/StaticTable/UYLFirstViewController.m rename to Archive/StaticTable/StaticTable/UYLFirstViewController.m diff --git a/Archive/StaticTable/StaticTable/UYLFirstViewController.xib b/Archive/StaticTable/StaticTable/UYLFirstViewController.xib new file mode 100644 index 0000000..8325205 --- /dev/null +++ b/Archive/StaticTable/StaticTable/UYLFirstViewController.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.h b/Archive/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.h similarity index 100% rename from StaticTable/StaticTable/UYLGeneralSettingsTableViewController.h rename to Archive/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.h diff --git a/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.m b/Archive/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.m similarity index 100% rename from StaticTable/StaticTable/UYLGeneralSettingsTableViewController.m rename to Archive/StaticTable/StaticTable/UYLGeneralSettingsTableViewController.m diff --git a/StaticTable/StaticTable/UYLRotatingTableViewController.h b/Archive/StaticTable/StaticTable/UYLRotatingTableViewController.h similarity index 100% rename from StaticTable/StaticTable/UYLRotatingTableViewController.h rename to Archive/StaticTable/StaticTable/UYLRotatingTableViewController.h diff --git a/StaticTable/StaticTable/UYLRotatingTableViewController.m b/Archive/StaticTable/StaticTable/UYLRotatingTableViewController.m similarity index 100% rename from StaticTable/StaticTable/UYLRotatingTableViewController.m rename to Archive/StaticTable/StaticTable/UYLRotatingTableViewController.m diff --git a/SyncMe/SyncMe/en.lproj/InfoPlist.strings b/Archive/StaticTable/StaticTable/en.lproj/InfoPlist.strings similarity index 100% rename from SyncMe/SyncMe/en.lproj/InfoPlist.strings rename to Archive/StaticTable/StaticTable/en.lproj/InfoPlist.strings diff --git a/StaticTable/StaticTable/first.png b/Archive/StaticTable/StaticTable/first.png similarity index 100% rename from StaticTable/StaticTable/first.png rename to Archive/StaticTable/StaticTable/first.png diff --git a/StaticTable/StaticTable/first@2x.png b/Archive/StaticTable/StaticTable/first@2x.png similarity index 100% rename from StaticTable/StaticTable/first@2x.png rename to Archive/StaticTable/StaticTable/first@2x.png diff --git a/StaticTable/StaticTable/main.m b/Archive/StaticTable/StaticTable/main.m similarity index 100% rename from StaticTable/StaticTable/main.m rename to Archive/StaticTable/StaticTable/main.m diff --git a/StaticTable/StaticTable/second.png b/Archive/StaticTable/StaticTable/second.png similarity index 100% rename from StaticTable/StaticTable/second.png rename to Archive/StaticTable/StaticTable/second.png diff --git a/StaticTable/StaticTable/second@2x.png b/Archive/StaticTable/StaticTable/second@2x.png similarity index 100% rename from StaticTable/StaticTable/second@2x.png rename to Archive/StaticTable/StaticTable/second@2x.png diff --git a/Stepper/Stepper.xcodeproj/project.pbxproj b/Archive/Stepper/Stepper.xcodeproj/project.pbxproj similarity index 81% rename from Stepper/Stepper.xcodeproj/project.pbxproj rename to Archive/Stepper/Stepper.xcodeproj/project.pbxproj index 3056532..9e328cf 100644 --- a/Stepper/Stepper.xcodeproj/project.pbxproj +++ b/Archive/Stepper/Stepper.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5334608F23CA627F00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLViewController.xib; sourceTree = ""; }; 53CA1FB714B3B08500432C8E /* Stepper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stepper.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53CA1FBB14B3B08500432C8E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 53CA1FBD14B3B08500432C8E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -30,7 +31,6 @@ 53CA1FCB14B3B08500432C8E /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; 53CA1FCD14B3B08500432C8E /* UYLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; 53CA1FCE14B3B08500432C8E /* UYLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; - 53CA1FD114B3B08500432C8E /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLViewController.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,14 +124,15 @@ 53CA1FAE14B3B08500432C8E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0430; + LastUpgradeCheck = 1120; }; buildConfigurationList = 53CA1FB114B3B08500432C8E /* Build configuration list for PBXProject "Stepper" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 53CA1FAC14B3B08500432C8E; productRefGroup = 53CA1FB814B3B08500432C8E /* Products */; @@ -180,7 +181,7 @@ 53CA1FD014B3B08500432C8E /* UYLViewController.xib */ = { isa = PBXVariantGroup; children = ( - 53CA1FD114B3B08500432C8E /* en */, + 5334608F23CA627F00BE943E /* Base */, ); name = UYLViewController.xib; sourceTree = ""; @@ -192,11 +193,31 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -204,10 +225,15 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -216,15 +242,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -238,6 +287,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Stepper/Stepper-Prefix.pch"; INFOPLIST_FILE = "Stepper/Stepper-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -250,6 +300,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Stepper/Stepper-Prefix.pch"; INFOPLIST_FILE = "Stepper/Stepper-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Archive/Stepper/Stepper/Base.lproj/UYLViewController.xib b/Archive/Stepper/Stepper/Base.lproj/UYLViewController.xib new file mode 100644 index 0000000..e957a6e --- /dev/null +++ b/Archive/Stepper/Stepper/Base.lproj/UYLViewController.xib @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stepper/Stepper/Stepper-Info.plist b/Archive/Stepper/Stepper/Stepper-Info.plist similarity index 94% rename from Stepper/Stepper/Stepper-Info.plist rename to Archive/Stepper/Stepper/Stepper-Info.plist index 82d3103..a5a6331 100644 --- a/Stepper/Stepper/Stepper-Info.plist +++ b/Archive/Stepper/Stepper/Stepper-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFiles CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Stepper/Stepper/Stepper-Prefix.pch b/Archive/Stepper/Stepper/Stepper-Prefix.pch similarity index 100% rename from Stepper/Stepper/Stepper-Prefix.pch rename to Archive/Stepper/Stepper/Stepper-Prefix.pch diff --git a/Stepper/Stepper/UYLAppDelegate.h b/Archive/Stepper/Stepper/UYLAppDelegate.h similarity index 100% rename from Stepper/Stepper/UYLAppDelegate.h rename to Archive/Stepper/Stepper/UYLAppDelegate.h diff --git a/Stepper/Stepper/UYLAppDelegate.m b/Archive/Stepper/Stepper/UYLAppDelegate.m similarity index 100% rename from Stepper/Stepper/UYLAppDelegate.m rename to Archive/Stepper/Stepper/UYLAppDelegate.m diff --git a/Stepper/Stepper/UYLViewController.h b/Archive/Stepper/Stepper/UYLViewController.h similarity index 100% rename from Stepper/Stepper/UYLViewController.h rename to Archive/Stepper/Stepper/UYLViewController.h diff --git a/Stepper/Stepper/UYLViewController.m b/Archive/Stepper/Stepper/UYLViewController.m similarity index 100% rename from Stepper/Stepper/UYLViewController.m rename to Archive/Stepper/Stepper/UYLViewController.m diff --git a/TaskTimer/TaskTimer/en.lproj/InfoPlist.strings b/Archive/Stepper/Stepper/en.lproj/InfoPlist.strings similarity index 100% rename from TaskTimer/TaskTimer/en.lproj/InfoPlist.strings rename to Archive/Stepper/Stepper/en.lproj/InfoPlist.strings diff --git a/Stepper/Stepper/main.m b/Archive/Stepper/Stepper/main.m similarity index 100% rename from Stepper/Stepper/main.m rename to Archive/Stepper/Stepper/main.m diff --git a/Styles/README b/Archive/Styles/README similarity index 94% rename from Styles/README rename to Archive/Styles/README index 463bf10..029456c 100644 --- a/Styles/README +++ b/Archive/Styles/README @@ -9,7 +9,7 @@ customise the appearance of common UIKit controls. For further details see: -useyourloaf.com/blog/2012/08/24/using-appearance-proxy-to-style-apps.html +useyourloaf.com/blog/using-appearance-proxy-to-style-apps/ ======================================================================= @@ -68,4 +68,4 @@ UYLRotatingViewController.h UYLRotatingViewController.m This is a container class used for all of the UIKit control views. The viewDidLoad method is used to set the view background. It also implements -the standard method to enable interface orientation. \ No newline at end of file +the standard method to enable interface orientation. diff --git a/Styles/Styles.xcodeproj/project.pbxproj b/Archive/Styles/Styles.xcodeproj/project.pbxproj similarity index 88% rename from Styles/Styles.xcodeproj/project.pbxproj rename to Archive/Styles/Styles.xcodeproj/project.pbxproj index 26e39d7..f63390f 100644 --- a/Styles/Styles.xcodeproj/project.pbxproj +++ b/Archive/Styles/Styles.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -13,6 +13,7 @@ 532F266715BDDF7A00321881 /* UYLRotatingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532F266615BDDF7A00321881 /* UYLRotatingViewController.m */; }; 532F267915BDE44F00321881 /* UYLResetButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 532F267815BDE44F00321881 /* UYLResetButton.m */; }; 532F267C15BDEAEB00321881 /* UYLStyleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532F267B15BDEAEB00321881 /* UYLStyleController.m */; }; + 5334608A23CA316E00BE943E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5334608923CA316E00BE943E /* LaunchScreen.storyboard */; }; 535734EA15B75876006F0E6A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 535734E915B75876006F0E6A /* UIKit.framework */; }; 535734EC15B75876006F0E6A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 535734EB15B75876006F0E6A /* Foundation.framework */; }; 535734EE15B75876006F0E6A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 535734ED15B75876006F0E6A /* CoreGraphics.framework */; }; @@ -51,6 +52,8 @@ 532F267815BDE44F00321881 /* UYLResetButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLResetButton.m; sourceTree = ""; }; 532F267A15BDEAEA00321881 /* UYLStyleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLStyleController.h; sourceTree = ""; }; 532F267B15BDEAEB00321881 /* UYLStyleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLStyleController.m; sourceTree = ""; }; + 5334608823CA30B700BE943E /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; + 5334608923CA316E00BE943E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 535734E515B75876006F0E6A /* Styles.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Styles.app; sourceTree = BUILT_PRODUCTS_DIR; }; 535734E915B75876006F0E6A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 535734EB15B75876006F0E6A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -101,6 +104,7 @@ 535734DA15B75875006F0E6A = { isa = PBXGroup; children = ( + 5334608823CA30B700BE943E /* README */, 535734EF15B75876006F0E6A /* Styles */, 535734E815B75876006F0E6A /* Frameworks */, 535734E615B75876006F0E6A /* Products */, @@ -145,6 +149,7 @@ 535734F215B75876006F0E6A /* InfoPlist.strings */, 535734F515B75877006F0E6A /* main.m */, 535734F715B75877006F0E6A /* Styles-Prefix.pch */, + 5334608923CA316E00BE943E /* LaunchScreen.storyboard */, ); name = "Supporting Files"; sourceTree = ""; @@ -228,14 +233,15 @@ isa = PBXProject; attributes = { CLASSPREFIX = UYL; - LastUpgradeCheck = 0430; + LastUpgradeCheck = 1120; }; buildConfigurationList = 535734DF15B75875006F0E6A /* Build configuration list for PBXProject "Styles" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 535734DA15B75875006F0E6A; productRefGroup = 535734E615B75876006F0E6A /* Products */; @@ -270,6 +276,7 @@ 53AA527915E58E9B000C8D04 /* back-button@2x.png in Resources */, 53AA527C15E591BF000C8D04 /* back-button-landscape.png in Resources */, 53AA527D15E591BF000C8D04 /* back-button-landscape@2x.png in Resources */, + 5334608A23CA316E00BE943E /* LaunchScreen.storyboard in Resources */, 5305B54615E6408500AC81F4 /* divider.png in Resources */, 5305B54715E6408500AC81F4 /* divider@2x.png in Resources */, ); @@ -311,12 +318,32 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -324,10 +351,14 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -336,16 +367,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -355,9 +408,11 @@ 5357350F15B75878006F0E6A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + DEVELOPMENT_TEAM = LCC2J94N44; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Styles/Styles-Prefix.pch"; INFOPLIST_FILE = "Styles/Styles-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -366,9 +421,11 @@ 5357351015B75878006F0E6A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + DEVELOPMENT_TEAM = LCC2J94N44; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Styles/Styles-Prefix.pch"; INFOPLIST_FILE = "Styles/Styles-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Archive/Styles/Styles/LaunchScreen.storyboard b/Archive/Styles/Styles/LaunchScreen.storyboard new file mode 100644 index 0000000..06d6044 --- /dev/null +++ b/Archive/Styles/Styles/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Styles/Styles/MainStoryboard.storyboard b/Archive/Styles/Styles/MainStoryboard.storyboard similarity index 66% rename from Styles/Styles/MainStoryboard.storyboard rename to Archive/Styles/Styles/MainStoryboard.storyboard index 494f317..e0db02c 100644 --- a/Styles/Styles/MainStoryboard.storyboard +++ b/Archive/Styles/Styles/MainStoryboard.storyboard @@ -1,123 +1,119 @@ - - + + + - - + + + - + - - - + + - + - - + + - - + - + - - + + - - + - + - - + + - - + - + - - + + - - + - + - - + + - - + @@ -132,45 +128,49 @@ + - + - + - + + + + - + - - + + - - + + - + - + - + + + + - + - - - - - - - - - - - - - + + - + - + - - + @@ -374,23 +366,27 @@ + - + - + - + + + + - + - - + + - - + + - + - + - + + + + - + - - + + @@ -423,79 +423,62 @@ - + + - + - + - + + + + - + - - + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/Styles/Styles/Resources/back-button-landscape.png b/Archive/Styles/Styles/Resources/back-button-landscape.png similarity index 100% rename from Styles/Styles/Resources/back-button-landscape.png rename to Archive/Styles/Styles/Resources/back-button-landscape.png diff --git a/Styles/Styles/Resources/back-button-landscape@2x.png b/Archive/Styles/Styles/Resources/back-button-landscape@2x.png similarity index 100% rename from Styles/Styles/Resources/back-button-landscape@2x.png rename to Archive/Styles/Styles/Resources/back-button-landscape@2x.png diff --git a/Styles/Styles/Resources/back-button.png b/Archive/Styles/Styles/Resources/back-button.png similarity index 100% rename from Styles/Styles/Resources/back-button.png rename to Archive/Styles/Styles/Resources/back-button.png diff --git a/Styles/Styles/Resources/back-button@2x.png b/Archive/Styles/Styles/Resources/back-button@2x.png similarity index 100% rename from Styles/Styles/Resources/back-button@2x.png rename to Archive/Styles/Styles/Resources/back-button@2x.png diff --git a/Styles/Styles/Resources/divider.png b/Archive/Styles/Styles/Resources/divider.png similarity index 100% rename from Styles/Styles/Resources/divider.png rename to Archive/Styles/Styles/Resources/divider.png diff --git a/Styles/Styles/Resources/divider@2x.png b/Archive/Styles/Styles/Resources/divider@2x.png similarity index 100% rename from Styles/Styles/Resources/divider@2x.png rename to Archive/Styles/Styles/Resources/divider@2x.png diff --git a/Styles/Styles/Resources/green-button.png b/Archive/Styles/Styles/Resources/green-button.png similarity index 100% rename from Styles/Styles/Resources/green-button.png rename to Archive/Styles/Styles/Resources/green-button.png diff --git a/Styles/Styles/Resources/green-button@2x.png b/Archive/Styles/Styles/Resources/green-button@2x.png similarity index 100% rename from Styles/Styles/Resources/green-button@2x.png rename to Archive/Styles/Styles/Resources/green-button@2x.png diff --git a/Styles/Styles/Resources/navbar-landscape.png b/Archive/Styles/Styles/Resources/navbar-landscape.png similarity index 100% rename from Styles/Styles/Resources/navbar-landscape.png rename to Archive/Styles/Styles/Resources/navbar-landscape.png diff --git a/Styles/Styles/Resources/navbar-landscape@2x.png b/Archive/Styles/Styles/Resources/navbar-landscape@2x.png similarity index 100% rename from Styles/Styles/Resources/navbar-landscape@2x.png rename to Archive/Styles/Styles/Resources/navbar-landscape@2x.png diff --git a/Styles/Styles/Resources/navbar.png b/Archive/Styles/Styles/Resources/navbar.png similarity index 100% rename from Styles/Styles/Resources/navbar.png rename to Archive/Styles/Styles/Resources/navbar.png diff --git a/Styles/Styles/Resources/navbar@2x.png b/Archive/Styles/Styles/Resources/navbar@2x.png similarity index 100% rename from Styles/Styles/Resources/navbar@2x.png rename to Archive/Styles/Styles/Resources/navbar@2x.png diff --git a/Styles/Styles/Resources/orange-button.png b/Archive/Styles/Styles/Resources/orange-button.png similarity index 100% rename from Styles/Styles/Resources/orange-button.png rename to Archive/Styles/Styles/Resources/orange-button.png diff --git a/Styles/Styles/Resources/orange-button@2x.png b/Archive/Styles/Styles/Resources/orange-button@2x.png similarity index 100% rename from Styles/Styles/Resources/orange-button@2x.png rename to Archive/Styles/Styles/Resources/orange-button@2x.png diff --git a/Styles/Styles/Resources/orange.png b/Archive/Styles/Styles/Resources/orange.png similarity index 100% rename from Styles/Styles/Resources/orange.png rename to Archive/Styles/Styles/Resources/orange.png diff --git a/Styles/Styles/Resources/orange@2x.png b/Archive/Styles/Styles/Resources/orange@2x.png similarity index 100% rename from Styles/Styles/Resources/orange@2x.png rename to Archive/Styles/Styles/Resources/orange@2x.png diff --git a/Styles/Styles/Resources/red-button.png b/Archive/Styles/Styles/Resources/red-button.png similarity index 100% rename from Styles/Styles/Resources/red-button.png rename to Archive/Styles/Styles/Resources/red-button.png diff --git a/Styles/Styles/Resources/red-button@2x.png b/Archive/Styles/Styles/Resources/red-button@2x.png similarity index 100% rename from Styles/Styles/Resources/red-button@2x.png rename to Archive/Styles/Styles/Resources/red-button@2x.png diff --git a/Styles/Styles/Resources/steel-button.png b/Archive/Styles/Styles/Resources/steel-button.png similarity index 100% rename from Styles/Styles/Resources/steel-button.png rename to Archive/Styles/Styles/Resources/steel-button.png diff --git a/Styles/Styles/Resources/steel-button@2x.png b/Archive/Styles/Styles/Resources/steel-button@2x.png similarity index 100% rename from Styles/Styles/Resources/steel-button@2x.png rename to Archive/Styles/Styles/Resources/steel-button@2x.png diff --git a/Styles/Styles/Styles-Info.plist b/Archive/Styles/Styles/Styles-Info.plist similarity index 91% rename from Styles/Styles/Styles-Info.plist rename to Archive/Styles/Styles/Styles-Info.plist index faa11bb..66a4d0c 100644 --- a/Styles/Styles/Styles-Info.plist +++ b/Archive/Styles/Styles/Styles-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -24,6 +24,8 @@ 1.0 LSRequiresIPhoneOS + UILaunchStoryboardName + LaunchScreen UIMainStoryboardFile MainStoryboard UIRequiredDeviceCapabilities diff --git a/Styles/Styles/Styles-Prefix.pch b/Archive/Styles/Styles/Styles-Prefix.pch similarity index 100% rename from Styles/Styles/Styles-Prefix.pch rename to Archive/Styles/Styles/Styles-Prefix.pch diff --git a/Styles/Styles/UYLAppDelegate.h b/Archive/Styles/Styles/UYLAppDelegate.h similarity index 100% rename from Styles/Styles/UYLAppDelegate.h rename to Archive/Styles/Styles/UYLAppDelegate.h diff --git a/Styles/Styles/UYLAppDelegate.m b/Archive/Styles/Styles/UYLAppDelegate.m similarity index 100% rename from Styles/Styles/UYLAppDelegate.m rename to Archive/Styles/Styles/UYLAppDelegate.m diff --git a/Styles/Styles/UYLListViewController.h b/Archive/Styles/Styles/UYLListViewController.h similarity index 100% rename from Styles/Styles/UYLListViewController.h rename to Archive/Styles/Styles/UYLListViewController.h diff --git a/Styles/Styles/UYLListViewController.m b/Archive/Styles/Styles/UYLListViewController.m similarity index 93% rename from Styles/Styles/UYLListViewController.m rename to Archive/Styles/Styles/UYLListViewController.m index eddda08..ca15048 100644 --- a/Styles/Styles/UYLListViewController.m +++ b/Archive/Styles/Styles/UYLListViewController.m @@ -37,9 +37,9 @@ @interface UYLListViewController () @implementation UYLListViewController -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} +//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +//{ +// return YES; +//} @end diff --git a/Styles/Styles/UYLOkButton.h b/Archive/Styles/Styles/UYLOkButton.h similarity index 100% rename from Styles/Styles/UYLOkButton.h rename to Archive/Styles/Styles/UYLOkButton.h diff --git a/Styles/Styles/UYLOkButton.m b/Archive/Styles/Styles/UYLOkButton.m similarity index 100% rename from Styles/Styles/UYLOkButton.m rename to Archive/Styles/Styles/UYLOkButton.m diff --git a/Styles/Styles/UYLResetButton.h b/Archive/Styles/Styles/UYLResetButton.h similarity index 100% rename from Styles/Styles/UYLResetButton.h rename to Archive/Styles/Styles/UYLResetButton.h diff --git a/Styles/Styles/UYLResetButton.m b/Archive/Styles/Styles/UYLResetButton.m similarity index 100% rename from Styles/Styles/UYLResetButton.m rename to Archive/Styles/Styles/UYLResetButton.m diff --git a/Styles/Styles/UYLRotatingViewController.h b/Archive/Styles/Styles/UYLRotatingViewController.h similarity index 100% rename from Styles/Styles/UYLRotatingViewController.h rename to Archive/Styles/Styles/UYLRotatingViewController.h diff --git a/Styles/Styles/UYLRotatingViewController.m b/Archive/Styles/Styles/UYLRotatingViewController.m similarity index 93% rename from Styles/Styles/UYLRotatingViewController.m rename to Archive/Styles/Styles/UYLRotatingViewController.m index 7333012..243d96f 100644 --- a/Styles/Styles/UYLRotatingViewController.m +++ b/Archive/Styles/Styles/UYLRotatingViewController.m @@ -41,9 +41,9 @@ - (void) viewDidLoad self.view.backgroundColor = [UIColor lightGrayColor]; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} +//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +//{ +// return YES; +//} @end diff --git a/Styles/Styles/UYLStyleController.h b/Archive/Styles/Styles/UYLStyleController.h similarity index 100% rename from Styles/Styles/UYLStyleController.h rename to Archive/Styles/Styles/UYLStyleController.h diff --git a/Styles/Styles/UYLStyleController.m b/Archive/Styles/Styles/UYLStyleController.m similarity index 98% rename from Styles/Styles/UYLStyleController.m rename to Archive/Styles/Styles/UYLStyleController.m index b12ad10..7310ba7 100644 --- a/Styles/Styles/UYLStyleController.m +++ b/Archive/Styles/Styles/UYLStyleController.m @@ -52,7 +52,7 @@ + (void)applyStyle [navigationBarAppearance setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault]; [navigationBarAppearance setBackgroundImage:navBarLandscapeImage forBarMetrics:UIBarMetricsLandscapePhone]; - NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor grayColor], UITextAttributeTextColor, nil]; + NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor grayColor], NSForegroundColorAttributeName, nil]; [navigationBarAppearance setTitleTextAttributes:textAttributes]; UIImage *backButtonImage = [UIImage imageNamed:@"back-button"]; diff --git a/Styles/Styles/UYLZeroButton.h b/Archive/Styles/Styles/UYLZeroButton.h similarity index 100% rename from Styles/Styles/UYLZeroButton.h rename to Archive/Styles/Styles/UYLZeroButton.h diff --git a/Styles/Styles/UYLZeroButton.m b/Archive/Styles/Styles/UYLZeroButton.m similarity index 100% rename from Styles/Styles/UYLZeroButton.m rename to Archive/Styles/Styles/UYLZeroButton.m diff --git a/TwitterSearch/TwitterSearch/en.lproj/InfoPlist.strings b/Archive/Styles/Styles/en.lproj/InfoPlist.strings similarity index 100% rename from TwitterSearch/TwitterSearch/en.lproj/InfoPlist.strings rename to Archive/Styles/Styles/en.lproj/InfoPlist.strings diff --git a/Styles/Styles/main.m b/Archive/Styles/Styles/main.m similarity index 100% rename from Styles/Styles/main.m rename to Archive/Styles/Styles/main.m diff --git a/SyncMe/SyncMe.xcodeproj/project.pbxproj b/Archive/SyncMe/SyncMe.xcodeproj/project.pbxproj similarity index 80% rename from SyncMe/SyncMe.xcodeproj/project.pbxproj rename to Archive/SyncMe/SyncMe.xcodeproj/project.pbxproj index b823bf1..df3f587 100644 --- a/SyncMe/SyncMe.xcodeproj/project.pbxproj +++ b/Archive/SyncMe/SyncMe.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -18,6 +18,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5334609523CA6B2500BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLViewController.xib; sourceTree = ""; }; 53DA6A481454A1C300368AB3 /* SyncMe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SyncMe.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53DA6A4C1454A1C300368AB3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 53DA6A4E1454A1C300368AB3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -30,7 +31,6 @@ 53DA6A5C1454A1C300368AB3 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; 53DA6A5E1454A1C300368AB3 /* UYLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; 53DA6A5F1454A1C400368AB3 /* UYLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; - 53DA6A621454A1C400368AB3 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLViewController.xib; sourceTree = ""; }; 53DA6A771454B39300368AB3 /* SyncMe.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = SyncMe.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ @@ -126,14 +126,15 @@ 53DA6A3F1454A1C300368AB3 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0420; + LastUpgradeCheck = 1120; }; buildConfigurationList = 53DA6A421454A1C300368AB3 /* Build configuration list for PBXProject "SyncMe" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 53DA6A3D1454A1C300368AB3; productRefGroup = 53DA6A491454A1C300368AB3 /* Products */; @@ -182,7 +183,7 @@ 53DA6A611454A1C400368AB3 /* UYLViewController.xib */ = { isa = PBXVariantGroup; children = ( - 53DA6A621454A1C400368AB3 /* en */, + 5334609523CA6B2500BE943E /* Base */, ); name = UYLViewController.xib; sourceTree = ""; @@ -194,11 +195,31 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -206,10 +227,15 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -218,15 +244,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -236,10 +285,12 @@ 53DA6A671454A1C400368AB3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_ENTITLEMENTS = SyncMe/SyncMe.entitlements; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SyncMe/SyncMe-Prefix.pch"; INFOPLIST_FILE = "SyncMe/SyncMe-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -248,10 +299,12 @@ 53DA6A681454A1C400368AB3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_ENTITLEMENTS = SyncMe/SyncMe.entitlements; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SyncMe/SyncMe-Prefix.pch"; INFOPLIST_FILE = "SyncMe/SyncMe-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/SyncMe/SyncMe/en.lproj/UYLViewController.xib b/Archive/SyncMe/SyncMe/Base.lproj/UYLViewController.xib similarity index 100% rename from SyncMe/SyncMe/en.lproj/UYLViewController.xib rename to Archive/SyncMe/SyncMe/Base.lproj/UYLViewController.xib diff --git a/SyncMe/SyncMe/SyncMe-Info.plist b/Archive/SyncMe/SyncMe/SyncMe-Info.plist similarity index 94% rename from SyncMe/SyncMe/SyncMe-Info.plist rename to Archive/SyncMe/SyncMe/SyncMe-Info.plist index f5d7a12..5da589d 100644 --- a/SyncMe/SyncMe/SyncMe-Info.plist +++ b/Archive/SyncMe/SyncMe/SyncMe-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFiles CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SyncMe/SyncMe/SyncMe-Prefix.pch b/Archive/SyncMe/SyncMe/SyncMe-Prefix.pch similarity index 100% rename from SyncMe/SyncMe/SyncMe-Prefix.pch rename to Archive/SyncMe/SyncMe/SyncMe-Prefix.pch diff --git a/SyncMe/SyncMe/SyncMe.entitlements b/Archive/SyncMe/SyncMe/SyncMe.entitlements similarity index 100% rename from SyncMe/SyncMe/SyncMe.entitlements rename to Archive/SyncMe/SyncMe/SyncMe.entitlements diff --git a/SyncMe/SyncMe/UYLAppDelegate.h b/Archive/SyncMe/SyncMe/UYLAppDelegate.h similarity index 100% rename from SyncMe/SyncMe/UYLAppDelegate.h rename to Archive/SyncMe/SyncMe/UYLAppDelegate.h diff --git a/SyncMe/SyncMe/UYLAppDelegate.m b/Archive/SyncMe/SyncMe/UYLAppDelegate.m similarity index 100% rename from SyncMe/SyncMe/UYLAppDelegate.m rename to Archive/SyncMe/SyncMe/UYLAppDelegate.m diff --git a/SyncMe/SyncMe/UYLViewController.h b/Archive/SyncMe/SyncMe/UYLViewController.h similarity index 100% rename from SyncMe/SyncMe/UYLViewController.h rename to Archive/SyncMe/SyncMe/UYLViewController.h diff --git a/SyncMe/SyncMe/UYLViewController.m b/Archive/SyncMe/SyncMe/UYLViewController.m similarity index 100% rename from SyncMe/SyncMe/UYLViewController.m rename to Archive/SyncMe/SyncMe/UYLViewController.m diff --git a/WorldFacts/WorldFacts/en.lproj/InfoPlist.strings b/Archive/SyncMe/SyncMe/en.lproj/InfoPlist.strings similarity index 100% rename from WorldFacts/WorldFacts/en.lproj/InfoPlist.strings rename to Archive/SyncMe/SyncMe/en.lproj/InfoPlist.strings diff --git a/SyncMe/SyncMe/main.m b/Archive/SyncMe/SyncMe/main.m similarity index 100% rename from SyncMe/SyncMe/main.m rename to Archive/SyncMe/SyncMe/main.m diff --git a/TCNibLoad/Classes/NewViewController.h b/Archive/TCNibLoad/Classes/NewViewController.h similarity index 100% rename from TCNibLoad/Classes/NewViewController.h rename to Archive/TCNibLoad/Classes/NewViewController.h diff --git a/TCNibLoad/Classes/NewViewController.m b/Archive/TCNibLoad/Classes/NewViewController.m similarity index 100% rename from TCNibLoad/Classes/NewViewController.m rename to Archive/TCNibLoad/Classes/NewViewController.m diff --git a/TCNibLoad/Classes/OldViewController.h b/Archive/TCNibLoad/Classes/OldViewController.h similarity index 100% rename from TCNibLoad/Classes/OldViewController.h rename to Archive/TCNibLoad/Classes/OldViewController.h diff --git a/TCNibLoad/Classes/OldViewController.m b/Archive/TCNibLoad/Classes/OldViewController.m similarity index 100% rename from TCNibLoad/Classes/OldViewController.m rename to Archive/TCNibLoad/Classes/OldViewController.m diff --git a/Archive/TCNibLoad/Classes/OldViewController.xib b/Archive/TCNibLoad/Classes/OldViewController.xib new file mode 100644 index 0000000..331aaf2 --- /dev/null +++ b/Archive/TCNibLoad/Classes/OldViewController.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TCNibLoad/Classes/TCNibLoadAppDelegate.h b/Archive/TCNibLoad/Classes/TCNibLoadAppDelegate.h similarity index 100% rename from TCNibLoad/Classes/TCNibLoadAppDelegate.h rename to Archive/TCNibLoad/Classes/TCNibLoadAppDelegate.h diff --git a/TCNibLoad/Classes/TCNibLoadAppDelegate.m b/Archive/TCNibLoad/Classes/TCNibLoadAppDelegate.m similarity index 100% rename from TCNibLoad/Classes/TCNibLoadAppDelegate.m rename to Archive/TCNibLoad/Classes/TCNibLoadAppDelegate.m diff --git a/Archive/TCNibLoad/LabelCell.xib b/Archive/TCNibLoad/LabelCell.xib new file mode 100644 index 0000000..3b87b28 --- /dev/null +++ b/Archive/TCNibLoad/LabelCell.xib @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TCNibLoad/MainWindow.xib b/Archive/TCNibLoad/MainWindow.xib new file mode 100644 index 0000000..36be6bd --- /dev/null +++ b/Archive/TCNibLoad/MainWindow.xib @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TCNibLoad/TCNibLoad-Info.plist b/Archive/TCNibLoad/TCNibLoad-Info.plist similarity index 92% rename from TCNibLoad/TCNibLoad-Info.plist rename to Archive/TCNibLoad/TCNibLoad-Info.plist index 3289444..276e6f6 100644 --- a/TCNibLoad/TCNibLoad-Info.plist +++ b/Archive/TCNibLoad/TCNibLoad-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFile CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj b/Archive/TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj similarity index 80% rename from TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj rename to Archive/TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj index e814942..f00f8fe 100644 --- a/TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj +++ b/Archive/TCNibLoad/TCNibLoad.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -140,15 +140,16 @@ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TCNibLoad" */; - compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 1; knownRegions = ( - English, - Japanese, - French, - German, + Base, + en, ); mainGroup = 29B97314FDCFA39411CA2CEA /* TCNibLoad */; projectDirPath = ""; @@ -191,16 +192,22 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Don't Code Sign"; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; + DEVELOPMENT_TEAM = LCC2J94N44; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = TCNibLoad_Prefix.pch; INFOPLIST_FILE = "TCNibLoad-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 3.1.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TCNibLoad; PRODUCT_NAME = TCNibLoad; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; @@ -208,14 +215,20 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Don't Code Sign"; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = YES; + DEVELOPMENT_TEAM = LCC2J94N44; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = TCNibLoad_Prefix.pch; INFOPLIST_FILE = "TCNibLoad-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 3.1.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TCNibLoad; PRODUCT_NAME = TCNibLoad; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; VALIDATE_PRODUCT = YES; }; name = Release; @@ -223,12 +236,36 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -236,13 +273,35 @@ C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - PREBINDING = NO; SDKROOT = iphoneos; }; name = Release; diff --git a/TCNibLoad/TCNibLoad_Prefix.pch b/Archive/TCNibLoad/TCNibLoad_Prefix.pch similarity index 100% rename from TCNibLoad/TCNibLoad_Prefix.pch rename to Archive/TCNibLoad/TCNibLoad_Prefix.pch diff --git a/TCNibLoad/main.m b/Archive/TCNibLoad/main.m similarity index 100% rename from TCNibLoad/main.m rename to Archive/TCNibLoad/main.m diff --git a/TaskTimer/README b/Archive/TaskTimer/README similarity index 95% rename from TaskTimer/README rename to Archive/TaskTimer/README index fd14c10..949762d 100644 --- a/TaskTimer/README +++ b/Archive/TaskTimer/README @@ -13,8 +13,8 @@ perform a list of tasks. For further details see: -http://useyourloaf.com/blog/2012/4/23/voiceover-accessibility.html -http://useyourloaf.com/blog/2012/5/14/detecting-voiceover-status-changes.html +https://useyourloaf.com/blog/voiceover-accessibility/ +https://useyourloaf.com/blog/detecting-voiceover-status-changes/ ======================================================================= Model diff --git a/TaskTimer/TaskTimer.xcodeproj/project.pbxproj b/Archive/TaskTimer/TaskTimer.xcodeproj/project.pbxproj similarity index 87% rename from TaskTimer/TaskTimer.xcodeproj/project.pbxproj rename to Archive/TaskTimer/TaskTimer.xcodeproj/project.pbxproj index b1fb648..c30bd55 100644 --- a/TaskTimer/TaskTimer.xcodeproj/project.pbxproj +++ b/Archive/TaskTimer/TaskTimer.xcodeproj/project.pbxproj @@ -44,10 +44,10 @@ 532DD95F1530C90300ED5845 /* UYLTaskViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTaskViewController.m; sourceTree = ""; }; 532DD96A1530C9AD00ED5845 /* UYLAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; 532DD96B1530C9AD00ED5845 /* UYLAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; - 532DD96E1530CA6400ED5845 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLTaskListViewController_iPad.xib; sourceTree = ""; }; - 532DD9701530CA6400ED5845 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLTaskListViewController_iPhone.xib; sourceTree = ""; }; - 532DD9721530CA6400ED5845 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLTaskViewController_iPad.xib; sourceTree = ""; }; - 532DD9741530CA6400ED5845 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/UYLTaskViewController_iPhone.xib; sourceTree = ""; }; + 5334608B23CA3B5E00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLTaskListViewController_iPad.xib; sourceTree = ""; }; + 5334608C23CA3B5E00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLTaskListViewController_iPhone.xib; sourceTree = ""; }; + 5334608D23CA3B5E00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLTaskViewController_iPad.xib; sourceTree = ""; }; + 5334608E23CA3B5E00BE943E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLTaskViewController_iPhone.xib; sourceTree = ""; }; 534644A4155F083D00B20849 /* redbutton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = redbutton.png; sourceTree = ""; }; 536270F1152E0A55009732E1 /* TaskTimer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TaskTimer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 536270F5152E0A55009732E1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -230,14 +230,15 @@ isa = PBXProject; attributes = { CLASSPREFIX = UYL; - LastUpgradeCheck = 0430; + LastUpgradeCheck = 1120; }; buildConfigurationList = 536270EB152E0A55009732E1 /* Build configuration list for PBXProject "TaskTimer" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 536270E6152E0A55009732E1; productRefGroup = 536270F2152E0A55009732E1 /* Products */; @@ -295,7 +296,7 @@ 532DD96D1530CA6400ED5845 /* UYLTaskListViewController_iPad.xib */ = { isa = PBXVariantGroup; children = ( - 532DD96E1530CA6400ED5845 /* en */, + 5334608B23CA3B5E00BE943E /* Base */, ); name = UYLTaskListViewController_iPad.xib; sourceTree = ""; @@ -303,7 +304,7 @@ 532DD96F1530CA6400ED5845 /* UYLTaskListViewController_iPhone.xib */ = { isa = PBXVariantGroup; children = ( - 532DD9701530CA6400ED5845 /* en */, + 5334608C23CA3B5E00BE943E /* Base */, ); name = UYLTaskListViewController_iPhone.xib; sourceTree = ""; @@ -311,7 +312,7 @@ 532DD9711530CA6400ED5845 /* UYLTaskViewController_iPad.xib */ = { isa = PBXVariantGroup; children = ( - 532DD9721530CA6400ED5845 /* en */, + 5334608D23CA3B5E00BE943E /* Base */, ); name = UYLTaskViewController_iPad.xib; sourceTree = ""; @@ -319,7 +320,7 @@ 532DD9731530CA6400ED5845 /* UYLTaskViewController_iPhone.xib */ = { isa = PBXVariantGroup; children = ( - 532DD9741530CA6400ED5845 /* en */, + 5334608E23CA3B5E00BE943E /* Base */, ); name = UYLTaskViewController_iPhone.xib; sourceTree = ""; @@ -339,12 +340,32 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -352,10 +373,14 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -365,16 +390,38 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -388,6 +435,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskTimer/TaskTimer-Prefix.pch"; INFOPLIST_FILE = "TaskTimer/TaskTimer-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -399,6 +447,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskTimer/TaskTimer-Prefix.pch"; INFOPLIST_FILE = "TaskTimer/TaskTimer-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPad.xib b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPad.xib new file mode 100644 index 0000000..f37ea5e --- /dev/null +++ b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPad.xib @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPhone.xib b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPhone.xib new file mode 100644 index 0000000..477fd87 --- /dev/null +++ b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskListViewController_iPhone.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPad.xib b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPad.xib new file mode 100644 index 0000000..1fd7bab --- /dev/null +++ b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPad.xib @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPhone.xib b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPhone.xib new file mode 100644 index 0000000..328cc4f --- /dev/null +++ b/Archive/TaskTimer/TaskTimer/Base.lproj/UYLTaskViewController_iPhone.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.h b/Archive/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.h similarity index 100% rename from TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.h rename to Archive/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.h diff --git a/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.m b/Archive/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.m similarity index 100% rename from TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.m rename to Archive/TaskTimer/TaskTimer/NSNumber+UYLTimeFormatter.m diff --git a/TaskTimer/TaskTimer/Task.h b/Archive/TaskTimer/TaskTimer/Task.h similarity index 100% rename from TaskTimer/TaskTimer/Task.h rename to Archive/TaskTimer/TaskTimer/Task.h diff --git a/TaskTimer/TaskTimer/Task.m b/Archive/TaskTimer/TaskTimer/Task.m similarity index 100% rename from TaskTimer/TaskTimer/Task.m rename to Archive/TaskTimer/TaskTimer/Task.m diff --git a/TaskTimer/TaskTimer/TaskTimer-Info.plist b/Archive/TaskTimer/TaskTimer/TaskTimer-Info.plist similarity index 95% rename from TaskTimer/TaskTimer/TaskTimer-Info.plist rename to Archive/TaskTimer/TaskTimer/TaskTimer-Info.plist index 3c50c87..363537d 100644 --- a/TaskTimer/TaskTimer/TaskTimer-Info.plist +++ b/Archive/TaskTimer/TaskTimer/TaskTimer-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TaskTimer/TaskTimer/TaskTimer-Prefix.pch b/Archive/TaskTimer/TaskTimer/TaskTimer-Prefix.pch similarity index 100% rename from TaskTimer/TaskTimer/TaskTimer-Prefix.pch rename to Archive/TaskTimer/TaskTimer/TaskTimer-Prefix.pch diff --git a/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/.xccurrentversion b/Archive/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/.xccurrentversion similarity index 100% rename from TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/.xccurrentversion rename to Archive/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/.xccurrentversion diff --git a/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/Accessibile.xcdatamodel/contents b/Archive/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/Accessibile.xcdatamodel/contents similarity index 100% rename from TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/Accessibile.xcdatamodel/contents rename to Archive/TaskTimer/TaskTimer/TaskTimer.xcdatamodeld/Accessibile.xcdatamodel/contents diff --git a/TaskTimer/TaskTimer/UYLAppDelegate.h b/Archive/TaskTimer/TaskTimer/UYLAppDelegate.h similarity index 100% rename from TaskTimer/TaskTimer/UYLAppDelegate.h rename to Archive/TaskTimer/TaskTimer/UYLAppDelegate.h diff --git a/TaskTimer/TaskTimer/UYLAppDelegate.m b/Archive/TaskTimer/TaskTimer/UYLAppDelegate.m similarity index 100% rename from TaskTimer/TaskTimer/UYLAppDelegate.m rename to Archive/TaskTimer/TaskTimer/UYLAppDelegate.m diff --git a/TaskTimer/TaskTimer/UYLCounterView.h b/Archive/TaskTimer/TaskTimer/UYLCounterView.h similarity index 100% rename from TaskTimer/TaskTimer/UYLCounterView.h rename to Archive/TaskTimer/TaskTimer/UYLCounterView.h diff --git a/TaskTimer/TaskTimer/UYLCounterView.m b/Archive/TaskTimer/TaskTimer/UYLCounterView.m similarity index 100% rename from TaskTimer/TaskTimer/UYLCounterView.m rename to Archive/TaskTimer/TaskTimer/UYLCounterView.m diff --git a/TaskTimer/TaskTimer/UYLTaskListViewController.h b/Archive/TaskTimer/TaskTimer/UYLTaskListViewController.h similarity index 100% rename from TaskTimer/TaskTimer/UYLTaskListViewController.h rename to Archive/TaskTimer/TaskTimer/UYLTaskListViewController.h diff --git a/TaskTimer/TaskTimer/UYLTaskListViewController.m b/Archive/TaskTimer/TaskTimer/UYLTaskListViewController.m similarity index 100% rename from TaskTimer/TaskTimer/UYLTaskListViewController.m rename to Archive/TaskTimer/TaskTimer/UYLTaskListViewController.m diff --git a/TaskTimer/TaskTimer/UYLTaskViewController.h b/Archive/TaskTimer/TaskTimer/UYLTaskViewController.h similarity index 100% rename from TaskTimer/TaskTimer/UYLTaskViewController.h rename to Archive/TaskTimer/TaskTimer/UYLTaskViewController.h diff --git a/TaskTimer/TaskTimer/UYLTaskViewController.m b/Archive/TaskTimer/TaskTimer/UYLTaskViewController.m similarity index 100% rename from TaskTimer/TaskTimer/UYLTaskViewController.m rename to Archive/TaskTimer/TaskTimer/UYLTaskViewController.m diff --git a/TaskTimer/TaskTimer/checked.png b/Archive/TaskTimer/TaskTimer/checked.png similarity index 100% rename from TaskTimer/TaskTimer/checked.png rename to Archive/TaskTimer/TaskTimer/checked.png diff --git a/TaskTimer/TaskTimer/checked@2x.png b/Archive/TaskTimer/TaskTimer/checked@2x.png similarity index 100% rename from TaskTimer/TaskTimer/checked@2x.png rename to Archive/TaskTimer/TaskTimer/checked@2x.png diff --git a/Archive/TaskTimer/TaskTimer/en.lproj/InfoPlist.strings b/Archive/TaskTimer/TaskTimer/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Archive/TaskTimer/TaskTimer/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/TaskTimer/TaskTimer/main.m b/Archive/TaskTimer/TaskTimer/main.m similarity index 100% rename from TaskTimer/TaskTimer/main.m rename to Archive/TaskTimer/TaskTimer/main.m diff --git a/TaskTimer/TaskTimer/redbutton.png b/Archive/TaskTimer/TaskTimer/redbutton.png similarity index 100% rename from TaskTimer/TaskTimer/redbutton.png rename to Archive/TaskTimer/TaskTimer/redbutton.png diff --git a/TaskTimer/TaskTimer/start.png b/Archive/TaskTimer/TaskTimer/start.png similarity index 100% rename from TaskTimer/TaskTimer/start.png rename to Archive/TaskTimer/TaskTimer/start.png diff --git a/TaskTimer/TaskTimer/start@2x.png b/Archive/TaskTimer/TaskTimer/start@2x.png similarity index 100% rename from TaskTimer/TaskTimer/start@2x.png rename to Archive/TaskTimer/TaskTimer/start@2x.png diff --git a/TaskTimer/TaskTimer/stop.png b/Archive/TaskTimer/TaskTimer/stop.png similarity index 100% rename from TaskTimer/TaskTimer/stop.png rename to Archive/TaskTimer/TaskTimer/stop.png diff --git a/TaskTimer/TaskTimer/stop@2x.png b/Archive/TaskTimer/TaskTimer/stop@2x.png similarity index 100% rename from TaskTimer/TaskTimer/stop@2x.png rename to Archive/TaskTimer/TaskTimer/stop@2x.png diff --git a/TaskTimer/TaskTimer/unchecked.png b/Archive/TaskTimer/TaskTimer/unchecked.png similarity index 100% rename from TaskTimer/TaskTimer/unchecked.png rename to Archive/TaskTimer/TaskTimer/unchecked.png diff --git a/TaskTimer/TaskTimer/unchecked@2x.png b/Archive/TaskTimer/TaskTimer/unchecked@2x.png similarity index 100% rename from TaskTimer/TaskTimer/unchecked@2x.png rename to Archive/TaskTimer/TaskTimer/unchecked@2x.png diff --git a/Archive/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj b/Archive/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7223dfd --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj @@ -0,0 +1,555 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 53432FE8176E71DF0015F986 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53432FE7176E71DF0015F986 /* Storyboard.storyboard */; }; + 5345C8501C32C16C00B88AB7 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 5345C84F1C32C16C00B88AB7 /* NSString+URLEncoding.m */; }; + 5345C8581C32CC3C00B88AB7 /* NSStringURLEncodingUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5345C8571C32CC3C00B88AB7 /* NSStringURLEncodingUnitTests.m */; }; + 536348091BA4AD6A005B59F3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 536348081BA4AD6A005B59F3 /* Images.xcassets */; }; + 5363480B1BA4B3C6005B59F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5363480A1BA4B3C6005B59F3 /* LaunchScreen.storyboard */; }; + 5363480E1BA4BB37005B59F3 /* TweetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5363480D1BA4BB37005B59F3 /* TweetCell.m */; }; + 53852EDA176B9A6900EC1107 /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53852ED9176B9A6900EC1107 /* Social.framework */; }; + 53852EDC176BA6DA00EC1107 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53852EDB176BA6DA00EC1107 /* Accounts.framework */; }; + 53CB80FE139D70FF0030ADD7 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB80FD139D70FF0030ADD7 /* UIKit.framework */; }; + 53CB8100139D70FF0030ADD7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB80FF139D70FF0030ADD7 /* Foundation.framework */; }; + 53CB8102139D70FF0030ADD7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */; }; + 53CB8108139D70FF0030ADD7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */; }; + 53CB810B139D70FF0030ADD7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB810A139D70FF0030ADD7 /* main.m */; }; + 53CB810E139D70FF0030ADD7 /* TwitterSearchAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */; }; + 53CB8114139D70FF0030ADD7 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8113139D70FF0030ADD7 /* RootViewController.m */; }; + 53CB812B139D73810030ADD7 /* SearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB812A139D73810030ADD7 /* SearchViewController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5345C85A1C32CC3C00B88AB7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 53CB80F0139D70FF0030ADD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 53CB80F8139D70FF0030ADD7; + remoteInfo = TwitterSearch; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 53432FE7176E71DF0015F986 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; + 5345C84E1C32C16C00B88AB7 /* NSString+URLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+URLEncoding.h"; sourceTree = ""; }; + 5345C84F1C32C16C00B88AB7 /* NSString+URLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+URLEncoding.m"; sourceTree = ""; }; + 5345C8551C32CC3C00B88AB7 /* TwitterSearchUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TwitterSearchUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5345C8571C32CC3C00B88AB7 /* NSStringURLEncodingUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSStringURLEncodingUnitTests.m; sourceTree = ""; }; + 5345C8591C32CC3C00B88AB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 536348081BA4AD6A005B59F3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5363480A1BA4B3C6005B59F3 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5363480C1BA4BB37005B59F3 /* TweetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TweetCell.h; sourceTree = ""; }; + 5363480D1BA4BB37005B59F3 /* TweetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TweetCell.m; sourceTree = ""; }; + 53852ED9176B9A6900EC1107 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; + 53852EDB176BA6DA00EC1107 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; + 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TwitterSearch.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53CB80FD139D70FF0030ADD7 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 53CB80FF139D70FF0030ADD7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 53CB8105139D70FF0030ADD7 /* TwitterSearch-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TwitterSearch-Info.plist"; sourceTree = ""; }; + 53CB8107139D70FF0030ADD7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 53CB810A139D70FF0030ADD7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53CB810C139D70FF0030ADD7 /* TwitterSearchAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TwitterSearchAppDelegate.h; sourceTree = ""; }; + 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TwitterSearchAppDelegate.m; sourceTree = ""; }; + 53CB8112139D70FF0030ADD7 /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; + 53CB8113139D70FF0030ADD7 /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; + 53CB8129139D73800030ADD7 /* SearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchViewController.h; sourceTree = ""; }; + 53CB812A139D73810030ADD7 /* SearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchViewController.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5345C8521C32CC3C00B88AB7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53CB80F6139D70FF0030ADD7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 53852EDC176BA6DA00EC1107 /* Accounts.framework in Frameworks */, + 53852EDA176B9A6900EC1107 /* Social.framework in Frameworks */, + 53CB80FE139D70FF0030ADD7 /* UIKit.framework in Frameworks */, + 53CB8100139D70FF0030ADD7 /* Foundation.framework in Frameworks */, + 53CB8102139D70FF0030ADD7 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5345C8561C32CC3C00B88AB7 /* TwitterSearchUnitTests */ = { + isa = PBXGroup; + children = ( + 5345C8571C32CC3C00B88AB7 /* NSStringURLEncodingUnitTests.m */, + 5345C8591C32CC3C00B88AB7 /* Info.plist */, + ); + path = TwitterSearchUnitTests; + sourceTree = ""; + }; + 53CB80EE139D70FF0030ADD7 = { + isa = PBXGroup; + children = ( + 53CB8103139D70FF0030ADD7 /* TwitterSearch */, + 5345C8561C32CC3C00B88AB7 /* TwitterSearchUnitTests */, + 53CB80FC139D70FF0030ADD7 /* Frameworks */, + 53CB80FA139D70FF0030ADD7 /* Products */, + ); + sourceTree = ""; + }; + 53CB80FA139D70FF0030ADD7 /* Products */ = { + isa = PBXGroup; + children = ( + 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */, + 5345C8551C32CC3C00B88AB7 /* TwitterSearchUnitTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 53CB80FC139D70FF0030ADD7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 53852EDB176BA6DA00EC1107 /* Accounts.framework */, + 53852ED9176B9A6900EC1107 /* Social.framework */, + 53CB80FD139D70FF0030ADD7 /* UIKit.framework */, + 53CB80FF139D70FF0030ADD7 /* Foundation.framework */, + 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 53CB8103139D70FF0030ADD7 /* TwitterSearch */ = { + isa = PBXGroup; + children = ( + 53CB810C139D70FF0030ADD7 /* TwitterSearchAppDelegate.h */, + 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */, + 53CB8112139D70FF0030ADD7 /* RootViewController.h */, + 53CB8113139D70FF0030ADD7 /* RootViewController.m */, + 53CB8129139D73800030ADD7 /* SearchViewController.h */, + 53CB812A139D73810030ADD7 /* SearchViewController.m */, + 5363480C1BA4BB37005B59F3 /* TweetCell.h */, + 5363480D1BA4BB37005B59F3 /* TweetCell.m */, + 53CB815C139D75DB0030ADD7 /* Resources */, + 536348081BA4AD6A005B59F3 /* Images.xcassets */, + 53CB8104139D70FF0030ADD7 /* Supporting Files */, + 5345C84E1C32C16C00B88AB7 /* NSString+URLEncoding.h */, + 5345C84F1C32C16C00B88AB7 /* NSString+URLEncoding.m */, + ); + path = TwitterSearch; + sourceTree = ""; + }; + 53CB8104139D70FF0030ADD7 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53CB8105139D70FF0030ADD7 /* TwitterSearch-Info.plist */, + 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */, + 53CB810A139D70FF0030ADD7 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53CB815C139D75DB0030ADD7 /* Resources */ = { + isa = PBXGroup; + children = ( + 53432FE7176E71DF0015F986 /* Storyboard.storyboard */, + 5363480A1BA4B3C6005B59F3 /* LaunchScreen.storyboard */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5345C8541C32CC3C00B88AB7 /* TwitterSearchUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5345C85C1C32CC3C00B88AB7 /* Build configuration list for PBXNativeTarget "TwitterSearchUnitTests" */; + buildPhases = ( + 5345C8511C32CC3C00B88AB7 /* Sources */, + 5345C8521C32CC3C00B88AB7 /* Frameworks */, + 5345C8531C32CC3C00B88AB7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5345C85B1C32CC3C00B88AB7 /* PBXTargetDependency */, + ); + name = TwitterSearchUnitTests; + productName = TwitterSearchUnitTests; + productReference = 5345C8551C32CC3C00B88AB7 /* TwitterSearchUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 53CB80F8139D70FF0030ADD7 /* TwitterSearch */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53CB811A139D70FF0030ADD7 /* Build configuration list for PBXNativeTarget "TwitterSearch" */; + buildPhases = ( + 53CB80F5139D70FF0030ADD7 /* Sources */, + 53CB80F6139D70FF0030ADD7 /* Frameworks */, + 53CB80F7139D70FF0030ADD7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TwitterSearch; + productName = TwitterSearch; + productReference = 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53CB80F0139D70FF0030ADD7 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + TargetAttributes = { + 5345C8541C32CC3C00B88AB7 = { + CreatedOnToolsVersion = 7.2; + TestTargetID = 53CB80F8139D70FF0030ADD7; + }; + 53CB80F8139D70FF0030ADD7 = { + DevelopmentTeam = LCC2J94N44; + }; + }; + }; + buildConfigurationList = 53CB80F3139D70FF0030ADD7 /* Build configuration list for PBXProject "TwitterSearch" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53CB80EE139D70FF0030ADD7; + productRefGroup = 53CB80FA139D70FF0030ADD7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53CB80F8139D70FF0030ADD7 /* TwitterSearch */, + 5345C8541C32CC3C00B88AB7 /* TwitterSearchUnitTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5345C8531C32CC3C00B88AB7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53CB80F7139D70FF0030ADD7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53CB8108139D70FF0030ADD7 /* InfoPlist.strings in Resources */, + 5363480B1BA4B3C6005B59F3 /* LaunchScreen.storyboard in Resources */, + 536348091BA4AD6A005B59F3 /* Images.xcassets in Resources */, + 53432FE8176E71DF0015F986 /* Storyboard.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5345C8511C32CC3C00B88AB7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5345C8581C32CC3C00B88AB7 /* NSStringURLEncodingUnitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53CB80F5139D70FF0030ADD7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5345C8501C32C16C00B88AB7 /* NSString+URLEncoding.m in Sources */, + 53CB810B139D70FF0030ADD7 /* main.m in Sources */, + 53CB810E139D70FF0030ADD7 /* TwitterSearchAppDelegate.m in Sources */, + 53CB8114139D70FF0030ADD7 /* RootViewController.m in Sources */, + 5363480E1BA4BB37005B59F3 /* TweetCell.m in Sources */, + 53CB812B139D73810030ADD7 /* SearchViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5345C85B1C32CC3C00B88AB7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 53CB80F8139D70FF0030ADD7 /* TwitterSearch */; + targetProxy = 5345C85A1C32CC3C00B88AB7 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53CB8107139D70FF0030ADD7 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5345C85D1C32CC3C00B88AB7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = TwitterSearchUnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TwitterSearchUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TwitterSearch.app/TwitterSearch"; + }; + name = Debug; + }; + 5345C85E1C32CC3C00B88AB7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = TwitterSearchUnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TwitterSearchUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TwitterSearch.app/TwitterSearch"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53CB8118139D70FF0030ADD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = ""; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 53CB8119139D70FF0030ADD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; + GCC_NO_COMMON_BLOCKS = YES; + GCC_VERSION = ""; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + }; + name = Release; + }; + 53CB811B139D70FF0030ADD7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + INFOPLIST_FILE = "TwitterSearch/TwitterSearch-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 53CB811C139D70FF0030ADD7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + INFOPLIST_FILE = "TwitterSearch/TwitterSearch-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5345C85C1C32CC3C00B88AB7 /* Build configuration list for PBXNativeTarget "TwitterSearchUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5345C85D1C32CC3C00B88AB7 /* Debug */, + 5345C85E1C32CC3C00B88AB7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53CB80F3139D70FF0030ADD7 /* Build configuration list for PBXProject "TwitterSearch" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53CB8118139D70FF0030ADD7 /* Debug */, + 53CB8119139D70FF0030ADD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53CB811A139D70FF0030ADD7 /* Build configuration list for PBXNativeTarget "TwitterSearch" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53CB811B139D70FF0030ADD7 /* Debug */, + 53CB811C139D70FF0030ADD7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53CB80F0139D70FF0030ADD7 /* Project object */; +} diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Contents.json b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..dd3842a --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon2-20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon2-20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon2-29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon2-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon2-40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon@2x-1.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon2-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon2-20@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon2-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon2-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon2-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon2-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon2-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon2-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon2-835@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon2-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29.png new file mode 100644 index 0000000..bc5e803 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x-1.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x-1.png new file mode 100644 index 0000000..532cc4f Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x-1.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x.png new file mode 100644 index 0000000..532cc4f Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png new file mode 100644 index 0000000..d828562 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40.png new file mode 100644 index 0000000..60a35d2 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x-1.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x-1.png new file mode 100644 index 0000000..54bc03a Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x-1.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x.png new file mode 100644 index 0000000..54bc03a Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-40@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76.png new file mode 100644 index 0000000..e87ceda Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76@2x.png new file mode 100644 index 0000000..ed4d620 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-76@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png new file mode 100644 index 0000000..70e3ba0 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x-1.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x-1.png new file mode 100644 index 0000000..ffb0d74 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x-1.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x.png new file mode 100644 index 0000000..ffb0d74 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@3x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@3x.png new file mode 100644 index 0000000..04587fb Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/Icon@3x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-1024.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-1024.png new file mode 100644 index 0000000..b628b9e Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-1024.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20.png new file mode 100644 index 0000000..08dee7a Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png new file mode 100644 index 0000000..d6fccd4 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png new file mode 100644 index 0000000..d6fccd4 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png new file mode 100644 index 0000000..fafe147 Binary files /dev/null and b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png differ diff --git a/Archive/TwitterSearch/TwitterSearch/Images.xcassets/Contents.json b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Archive/TwitterSearch/TwitterSearch/LaunchScreen.storyboard b/Archive/TwitterSearch/TwitterSearch/LaunchScreen.storyboard new file mode 100644 index 0000000..b3944d6 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.h b/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.h new file mode 100644 index 0000000..b72204d --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.h @@ -0,0 +1,81 @@ +// +// NSString+URLEncoding.h +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +/** + An NSString category that provides percent encoding of URL + strings following RFC 3986 or the W3C HTML specification. + */ + +@interface NSString (URLEncoding) + +/** + Returns a new string made from the receiver by replacing characters which are + reserved in a URI query with percent encoded characters. + + @discussion The following characters are not considered reserved in a URI query + by RFC 3986: + + - Alpha "a...z" "A...Z" + - Numberic "0...9" + - Unreserved "-._~" + + In addition the reserved characters "/" and "?" have no reserved purpose in the + query component of a URI so do not need to be percent escaped. + + @return Returns the encoded string, or nil if the transformation is not possible. + */ + +- (nullable NSString *)stringByAddingPercentEncodingForRFC3986; + +/** + Returns a new string made from the receiver by replacing characters which are + reserved in HTML forms (media type application/x-www-form-urlencoded) with + percent encoded characters. + + @discussion The W3C HTML5 specification, section 4.10.22.5 URL-encoded form + data percent encodes all characters except the following: + + - Space (0x20) is replaced by a "+" (0x2B) + - Bytes in the range 0x2A, 0x2D, 0x2E, 0x30-0x39, 0x41-0x5A, 0x5F, 0x61-0x7A + (alphanumeric + "*-._") + + @param plusForSpace Boolean, when true replaces space with a '+' + otherwise uses percent encoding (%20). Default is false. + + @return Returns the encoded string, or nil if the transformation is not possible. + */ + +- (nullable NSString *)stringByAddingPercentEncodingForFormData:(BOOL)plusForSpace; +@end diff --git a/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.m b/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.m new file mode 100644 index 0000000..a8568e3 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/NSString+URLEncoding.m @@ -0,0 +1,60 @@ +// +// NSString+URLEncoding.m +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "NSString+URLEncoding.h" + +@implementation NSString (URLEncoding) + +- (nullable NSString *)stringByAddingPercentEncodingForRFC3986 { + NSString *unreserved = @"-._~/?"; + NSMutableCharacterSet *allowedCharacterSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacterSet addCharactersInString:unreserved]; + return [self stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; +} + +- (nullable NSString *)stringByAddingPercentEncodingForFormData:(BOOL)plusForSpace { + NSString *unreserved = @"*-._"; + NSMutableCharacterSet *allowedCharacterSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacterSet addCharactersInString:unreserved]; + if (plusForSpace) { + [allowedCharacterSet addCharactersInString:@" "]; + } + + NSString *encoded = [self stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; + if (plusForSpace) { + encoded = [encoded stringByReplacingOccurrencesOfString:@" " withString:@"+"]; + } + return encoded; +} + +@end diff --git a/TwitterSearch/TwitterSearch/RootViewController.h b/Archive/TwitterSearch/TwitterSearch/RootViewController.h similarity index 100% rename from TwitterSearch/TwitterSearch/RootViewController.h rename to Archive/TwitterSearch/TwitterSearch/RootViewController.h diff --git a/TwitterSearch/TwitterSearch/RootViewController.m b/Archive/TwitterSearch/TwitterSearch/RootViewController.m similarity index 77% rename from TwitterSearch/TwitterSearch/RootViewController.m rename to Archive/TwitterSearch/TwitterSearch/RootViewController.m index ed1c6cb..9df71dd 100644 --- a/TwitterSearch/TwitterSearch/RootViewController.m +++ b/Archive/TwitterSearch/TwitterSearch/RootViewController.m @@ -1,7 +1,7 @@ // // RootViewController.m // Created by Keith Harrison on 06-June-2011 http://useyourloaf.com -// Copyright (c) 2011 Keith Harrison. All rights reserved. +// Copyright (c) 2011-2015 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -33,29 +33,32 @@ @implementation RootViewController -- (void)dealloc -{ - [super dealloc]; -} +#pragma mark - +#pragma mark === Text field delegate methods === +#pragma mark - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return YES; +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + if (textField.text) + { + [self performSegueWithIdentifier:@"SegueSearchView" sender:textField]; + } + [textField resignFirstResponder]; + return YES; } #pragma mark - -#pragma mark === Text field delegate methods === +#pragma mark === Segue === #pragma mark - -- (BOOL)textFieldShouldReturn:(UITextField *)textField { - - if (textField.text) { - SearchViewController *viewController = [[SearchViewController alloc] initWithNibName:@"SearchViewController" bundle:nil]; +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + if ([segue.identifier isEqualToString:@"SegueSearchView"]) + { + UITextField *textField = sender; + SearchViewController *viewController = segue.destinationViewController; viewController.query = [NSString stringWithFormat:@"%@", textField.text]; - [[self navigationController] pushViewController:viewController animated:YES]; - [viewController release]; } - [textField resignFirstResponder]; - return YES; } @end diff --git a/TwitterSearch/TwitterSearch/SearchViewController.h b/Archive/TwitterSearch/TwitterSearch/SearchViewController.h similarity index 84% rename from TwitterSearch/TwitterSearch/SearchViewController.h rename to Archive/TwitterSearch/TwitterSearch/SearchViewController.h index cbe2726..09e1bff 100644 --- a/TwitterSearch/TwitterSearch/SearchViewController.h +++ b/Archive/TwitterSearch/TwitterSearch/SearchViewController.h @@ -1,7 +1,7 @@ // // SearchViewController.h // Created by Keith Harrison on 06-June-2011 http://useyourloaf.com -// Copyright (c) 2011 Keith Harrison. All rights reserved. +// Copyright (c) 2013 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -31,13 +31,8 @@ #import -@interface SearchViewController : UITableViewController { - -} +@interface SearchViewController : UITableViewController @property (nonatomic, copy) NSString *query; -@property (nonatomic, retain) NSURLConnection *connection; -@property (nonatomic, retain) NSMutableData *buffer; -@property (nonatomic, retain) NSMutableArray *results; @end diff --git a/Archive/TwitterSearch/TwitterSearch/SearchViewController.m b/Archive/TwitterSearch/TwitterSearch/SearchViewController.m new file mode 100644 index 0000000..40cfbfb --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/SearchViewController.m @@ -0,0 +1,281 @@ +// +// SearchViewController.m +// Created by Keith Harrison on 06-June-2011 http://useyourloaf.com +// Copyright (c) 2013-2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "SearchViewController.h" +#import "TweetCell.h" +#import "NSString+URLEncoding.h" +#import +#import + +typedef NS_ENUM(NSUInteger, UYLTwitterSearchState) +{ + UYLTwitterSearchStateLoading, + UYLTwitterSearchStateNotFound, + UYLTwitterSearchStateRefused, + UYLTwitterSearchStateFailed +}; + +@interface SearchViewController () + +@property (nonatomic,strong) NSURLConnection *connection; +@property (nonatomic,strong) NSMutableData *buffer; +@property (nonatomic,strong) NSMutableArray *results; +@property (nonatomic,strong) ACAccountStore *accountStore; +@property (nonatomic,assign) UYLTwitterSearchState searchState; + +@end + +@implementation SearchViewController + +- (ACAccountStore *)accountStore +{ + if (_accountStore == nil) + { + _accountStore = [[ACAccountStore alloc] init]; + } + return _accountStore; +} + +- (NSString *)searchMessageForState:(UYLTwitterSearchState)state +{ + switch (state) + { + case UYLTwitterSearchStateLoading: + return @"Loading..."; + break; + case UYLTwitterSearchStateNotFound: + return @"No results found"; + break; + case UYLTwitterSearchStateRefused: + return @"Twitter Access Refused"; + break; + default: + return @"Not Available"; + break; + } +} + +- (IBAction)refreshSearchResults +{ + [self cancelConnection]; + [self loadQuery]; +} + +#pragma mark - +#pragma mark === View Setup === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.tableView.estimatedRowHeight = 84; + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.title = self.query; + [self loadQuery]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [self cancelConnection]; +} + +- (void)dealloc +{ + [self cancelConnection]; +} + +#pragma mark - +#pragma mark === UITableViewDataSource Delegates === +#pragma mark - + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + NSUInteger count = [self.results count]; + return count > 0 ? count : 1; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *ResultCellIdentifier = @"ResultCell"; + static NSString *LoadCellIdentifier = @"LoadingCell"; + + NSUInteger count = [self.results count]; + if ((count == 0) && (indexPath.row == 0)) + { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LoadCellIdentifier]; + cell.textLabel.text = [self searchMessageForState:self.searchState]; + cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + return cell; + } + + TweetCell *cell = [tableView dequeueReusableCellWithIdentifier:ResultCellIdentifier]; + NSDictionary *tweet = (self.results)[indexPath.row]; + cell.tweetMessage.text = tweet[@"text"]; + cell.tweetMessage.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + return cell; +} + +- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.row & 1) + { + cell.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0]; + } + else + { + cell.backgroundColor = [UIColor whiteColor]; + } +} + +#pragma mark - +#pragma mark === Private methods === +#pragma mark - + +#define RESULTS_PERPAGE @"100" + +- (void)loadQuery +{ + self.searchState = UYLTwitterSearchStateLoading; + NSString *encodedQuery = [self.query stringByAddingPercentEncodingForFormData:NO]; + ACAccountType *accountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; + [self.accountStore requestAccessToAccountsWithType:accountType + options:NULL + completion:^(BOOL granted, NSError *error) + { + if (granted) + { + NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1.1/search/tweets.json"]; + NSDictionary *parameters = @{@"count" : RESULTS_PERPAGE, + @"q" : encodedQuery}; + + SLRequest *slRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter + requestMethod:SLRequestMethodGET + URL:url + parameters:parameters]; + + NSArray *accounts = [self.accountStore accountsWithAccountType:accountType]; + slRequest.account = [accounts lastObject]; + NSURLRequest *request = [slRequest preparedURLRequest]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; + }); + } + else + { + self.searchState = UYLTwitterSearchStateRefused; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.tableView reloadData]; + }); + } + }]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + self.buffer = [NSMutableData data]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + + [self.buffer appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + self.connection = nil; + + NSError *jsonParsingError = nil; + NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData:self.buffer options:0 error:&jsonParsingError]; + + self.results = jsonResults[@"statuses"]; + if ([self.results count] == 0) + { + NSArray *errors = jsonResults[@"errors"]; + if ([errors count]) + { + self.searchState = UYLTwitterSearchStateFailed; + } + else + { + self.searchState = UYLTwitterSearchStateNotFound; + } + } + + self.buffer = nil; + [self.refreshControl endRefreshing]; + [self.tableView reloadData]; + [self.tableView flashScrollIndicators]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + self.connection = nil; + self.buffer = nil; + [self.refreshControl endRefreshing]; + self.searchState = UYLTwitterSearchStateFailed; + + [self handleError:error]; + [self.tableView reloadData]; +} + +- (void)handleError:(NSError *)error +{ + NSString *errorMessage = [error localizedDescription]; + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Connection Error" + message:errorMessage + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alertView show]; +} + +- (void)cancelConnection +{ + if (self.connection != nil) + { + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + [self.connection cancel]; + self.connection = nil; + self.buffer = nil; + } +} + +@end + diff --git a/Archive/TwitterSearch/TwitterSearch/Storyboard.storyboard b/Archive/TwitterSearch/TwitterSearch/Storyboard.storyboard new file mode 100644 index 0000000..4739dc5 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/Storyboard.storyboard @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Archive/TwitterSearch/TwitterSearch/TweetCell.h b/Archive/TwitterSearch/TwitterSearch/TweetCell.h new file mode 100644 index 0000000..58da243 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/TweetCell.h @@ -0,0 +1,40 @@ +// +// TweetCell.h +// TwitterSearch +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface TweetCell : UITableViewCell +@property (weak, nonatomic) IBOutlet UILabel *tweetMessage; + +@end diff --git a/Archive/TwitterSearch/TwitterSearch/TweetCell.m b/Archive/TwitterSearch/TwitterSearch/TweetCell.m new file mode 100644 index 0000000..d13b327 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/TweetCell.m @@ -0,0 +1,40 @@ +// +// TweetCell.m +// TwitterSearch +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "TweetCell.h" + +@implementation TweetCell + + +@end diff --git a/Archive/TwitterSearch/TwitterSearch/TwitterSearch-Info.plist b/Archive/TwitterSearch/TwitterSearch/TwitterSearch-Info.plist new file mode 100644 index 0000000..daddcd6 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/TwitterSearch-Info.plist @@ -0,0 +1,52 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.0 + CFBundleSignature + ???? + CFBundleVersion + 2.0 + LSApplicationCategoryType + + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Storyboard + NSAppTransportSecurity + + NSExceptionDomains + + api.twitter.com + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h b/Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h similarity index 91% rename from TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h rename to Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h index 993bb47..6d5d5db 100644 --- a/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h +++ b/Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.h @@ -30,11 +30,8 @@ #import -@interface TwitterSearchAppDelegate : NSObject { +@interface TwitterSearchAppDelegate : NSObject -} - -@property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, retain) IBOutlet UINavigationController *navigationController; +@property (nonatomic, strong) UIWindow *window; @end diff --git a/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m b/Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m similarity index 86% rename from TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m rename to Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m index d0dda3f..55d024c 100644 --- a/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m +++ b/Archive/TwitterSearch/TwitterSearch/TwitterSearchAppDelegate.m @@ -32,21 +32,10 @@ @implementation TwitterSearchAppDelegate -@synthesize window=_window; -@synthesize navigationController=_navigationController; - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window.rootViewController = self.navigationController; - [self.window makeKeyAndVisible]; return YES; } -- (void)dealloc -{ - [_window release]; - [_navigationController release]; - [super dealloc]; -} @end diff --git a/Archive/TwitterSearch/TwitterSearch/en.lproj/InfoPlist.strings b/Archive/TwitterSearch/TwitterSearch/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Archive/TwitterSearch/TwitterSearch/main.m b/Archive/TwitterSearch/TwitterSearch/main.m new file mode 100644 index 0000000..69177a4 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearch/main.m @@ -0,0 +1,41 @@ +// +// main.m +// TwitterSearch +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import +#import "TwitterSearchAppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([TwitterSearchAppDelegate class])); + } +} diff --git a/Archive/TwitterSearch/TwitterSearchUnitTests/Info.plist b/Archive/TwitterSearch/TwitterSearchUnitTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearchUnitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Archive/TwitterSearch/TwitterSearchUnitTests/NSStringURLEncodingUnitTests.m b/Archive/TwitterSearch/TwitterSearchUnitTests/NSStringURLEncodingUnitTests.m new file mode 100644 index 0000000..c791a5e --- /dev/null +++ b/Archive/TwitterSearch/TwitterSearchUnitTests/NSStringURLEncodingUnitTests.m @@ -0,0 +1,140 @@ +// +// NSStringURLEncodingUnitTests.m +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "NSString+URLEncoding.h" +#import + +@interface NSStringURLEncodingUnitTests : XCTestCase + +@end + +@implementation NSStringURLEncodingUnitTests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testRFC3986AlphaNumericNotEncoded { + NSString *input = @"abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + XCTAssertEqualObjects(input, output); +} + +- (void)testFormAlphaNumericNotEncoded { + NSString *input = @"abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + NSString *output = [input stringByAddingPercentEncodingForFormData:NO]; + XCTAssertEqualObjects(input, output); +} + +- (void)testRFC3986UnreservedNotEncoded { + NSString *input = @"-._~"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + XCTAssertEqualObjects(input, output); +} + +- (void)testRFC3986SlashQuestionNotEncoded { + NSString *input = @"/?"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + XCTAssertEqualObjects(input, output); +} + +- (void)testFormUnreservedNotEncoded { + NSString *input = @"*-._"; + NSString *output = [input stringByAddingPercentEncodingForFormData:NO]; + XCTAssertEqualObjects(input, output); +} + +- (void)testQuerySpacePercentEncoded { + NSString *input = @"one two"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + NSString *expected = @"one%20two"; + XCTAssertEqualObjects(expected, output); +} + +- (void)testFormSpacePercentEncoded { + NSString *input = @"one two"; + NSString *output = [input stringByAddingPercentEncodingForFormData:NO]; + NSString *expected = @"one%20two"; + XCTAssertEqualObjects(expected, output); +} + +- (void)testFormSpacePlusEncoded { + NSString *input = @"one two"; + NSString *output = [input stringByAddingPercentEncodingForFormData:YES]; + NSString *expected = @"one+two"; + XCTAssertEqualObjects(expected, output); +} + +- (void) testFormPlusIsPercentEncoded { + NSString *input = @"one+two"; + NSString *output = [input stringByAddingPercentEncodingForFormData:YES]; + NSString *expected = @"one%2Btwo"; + XCTAssertEqualObjects(expected, output); +} + +- (void) testQueryPercentPercentEncoded { + NSString *input = @"%"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + NSString *expected = @"%25"; + XCTAssertEqualObjects(expected, output); +} + +- (void) testFormPercentPercentEncoded { + NSString *input = @"%"; + NSString *output = [input stringByAddingPercentEncodingForFormData:NO]; + NSString *expected = @"%25"; + XCTAssertEqualObjects(expected, output); +} + +- (void) testQueryReservedPercentEncoded { + NSString *input = @"!#$&'()*+,:;=@[]"; + NSString *output = [input stringByAddingPercentEncodingForRFC3986]; + NSString *expected = @"%21%23%24%26%27%28%29%2A%2B%2C%3A%3B%3D%40%5B%5D"; + XCTAssertEqualObjects(expected, output); +} + +- (void) testFormReservedPercentEncoded { + NSString *input = @"!#$&'()+,/:;=?@[]"; + NSString *output = [input stringByAddingPercentEncodingForFormData:NO]; + NSString *expected = @"%21%23%24%26%27%28%29%2B%2C%2F%3A%3B%3D%3F%40%5B%5D"; + XCTAssertEqualObjects(expected, output); +} + +@end diff --git a/AutoLayout/AutoLayout.xcodeproj/project.pbxproj b/AutoLayout/AutoLayout.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d37e045 --- /dev/null +++ b/AutoLayout/AutoLayout.xcodeproj/project.pbxproj @@ -0,0 +1,376 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 47; + objects = { + +/* Begin PBXBuildFile section */ + 5319D0191CA6E8C1009E4AFA /* AdaptiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5319D0181CA6E8C1009E4AFA /* AdaptiveViewController.swift */; }; + 5329F1161C79008300A35954 /* LayoutAnchorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5329F1151C79008300A35954 /* LayoutAnchorController.swift */; }; + 53358D6F1C80F0B100C1842A /* LayoutGuideController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53358D6E1C80F0B100C1842A /* LayoutGuideController.swift */; }; + 535078741CBAD4D400700816 /* RTLViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535078731CBAD4D400700816 /* RTLViewController.swift */; }; + 5362E7F81C53F1B200DAA88B /* CenterAlignViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5362E7F71C53F1B200DAA88B /* CenterAlignViewController.swift */; }; + 53D6A5F11C53BF5200A81A14 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D6A5F01C53BF5200A81A14 /* AppDelegate.swift */; }; + 53D6A5F31C53BF5200A81A14 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D6A5F21C53BF5200A81A14 /* MasterViewController.swift */; }; + 53D6A5F81C53BF5200A81A14 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D6A5F61C53BF5200A81A14 /* Main.storyboard */; }; + 53D6A5FA1C53BF5200A81A14 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53D6A5F91C53BF5200A81A14 /* Assets.xcassets */; }; + 53D6A5FD1C53BF5200A81A14 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D6A5FB1C53BF5200A81A14 /* LaunchScreen.storyboard */; }; + 53EDF4081C5D5C78009F91EA /* StackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EDF4071C5D5C78009F91EA /* StackViewController.swift */; }; + 53EDF40A1C5D64C1009F91EA /* UIStackView+addView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EDF4091C5D64C0009F91EA /* UIStackView+addView.swift */; }; + 53EDF40C1C5D6641009F91EA /* UIViewController+addView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EDF40B1C5D6641009F91EA /* UIViewController+addView.swift */; }; + 53EDF40F1C5D66AA009F91EA /* UIViewController+Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EDF40E1C5D66AA009F91EA /* UIViewController+Constraint.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5319D0181CA6E8C1009E4AFA /* AdaptiveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdaptiveViewController.swift; sourceTree = ""; }; + 5329F1151C79008300A35954 /* LayoutAnchorController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutAnchorController.swift; sourceTree = ""; }; + 53358D6E1C80F0B100C1842A /* LayoutGuideController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutGuideController.swift; sourceTree = ""; }; + 535078731CBAD4D400700816 /* RTLViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTLViewController.swift; sourceTree = ""; }; + 535078751CBADA0C00700816 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = ""; }; + 535078761CBADA0C00700816 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = ""; }; + 5362E7F71C53F1B200DAA88B /* CenterAlignViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = CenterAlignViewController.swift; sourceTree = ""; tabWidth = 4; }; + 53D6A5ED1C53BF5200A81A14 /* AutoLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoLayout.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53D6A5F01C53BF5200A81A14 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53D6A5F21C53BF5200A81A14 /* MasterViewController.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; tabWidth = 4; }; + 53D6A5F71C53BF5200A81A14 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53D6A5F91C53BF5200A81A14 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53D6A5FC1C53BF5200A81A14 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53D6A5FE1C53BF5200A81A14 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53EDF4071C5D5C78009F91EA /* StackViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackViewController.swift; sourceTree = ""; }; + 53EDF4091C5D64C0009F91EA /* UIStackView+addView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStackView+addView.swift"; sourceTree = ""; }; + 53EDF40B1C5D6641009F91EA /* UIViewController+addView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+addView.swift"; sourceTree = ""; }; + 53EDF40E1C5D66AA009F91EA /* UIViewController+Constraint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Constraint.swift"; sourceTree = ""; }; + 53EDF4101C5D77A7009F91EA /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53D6A5EA1C53BF5200A81A14 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53D6A5E41C53BF5200A81A14 = { + isa = PBXGroup; + children = ( + 53EDF4101C5D77A7009F91EA /* README.md */, + 53D6A5EF1C53BF5200A81A14 /* AutoLayout */, + 53D6A5EE1C53BF5200A81A14 /* Products */, + ); + indentWidth = 4; + sourceTree = ""; + tabWidth = 4; + }; + 53D6A5EE1C53BF5200A81A14 /* Products */ = { + isa = PBXGroup; + children = ( + 53D6A5ED1C53BF5200A81A14 /* AutoLayout.app */, + ); + name = Products; + sourceTree = ""; + }; + 53D6A5EF1C53BF5200A81A14 /* AutoLayout */ = { + isa = PBXGroup; + children = ( + 53EDF40D1C5D6653009F91EA /* Extensions */, + 53D6A5F01C53BF5200A81A14 /* AppDelegate.swift */, + 53D6A5F21C53BF5200A81A14 /* MasterViewController.swift */, + 5362E7F71C53F1B200DAA88B /* CenterAlignViewController.swift */, + 535078731CBAD4D400700816 /* RTLViewController.swift */, + 5329F1151C79008300A35954 /* LayoutAnchorController.swift */, + 53358D6E1C80F0B100C1842A /* LayoutGuideController.swift */, + 53EDF4071C5D5C78009F91EA /* StackViewController.swift */, + 5319D0181CA6E8C1009E4AFA /* AdaptiveViewController.swift */, + 53D6A5F61C53BF5200A81A14 /* Main.storyboard */, + 53D6A5F91C53BF5200A81A14 /* Assets.xcassets */, + 53D6A5FB1C53BF5200A81A14 /* LaunchScreen.storyboard */, + 53D6A5FE1C53BF5200A81A14 /* Info.plist */, + ); + path = AutoLayout; + sourceTree = ""; + }; + 53EDF40D1C5D6653009F91EA /* Extensions */ = { + isa = PBXGroup; + children = ( + 53EDF40B1C5D6641009F91EA /* UIViewController+addView.swift */, + 53EDF4091C5D64C0009F91EA /* UIStackView+addView.swift */, + 53EDF40E1C5D66AA009F91EA /* UIViewController+Constraint.swift */, + ); + name = Extensions; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53D6A5EC1C53BF5200A81A14 /* AutoLayout */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53D6A6011C53BF5200A81A14 /* Build configuration list for PBXNativeTarget "AutoLayout" */; + buildPhases = ( + 53D6A5E91C53BF5200A81A14 /* Sources */, + 53D6A5EA1C53BF5200A81A14 /* Frameworks */, + 53D6A5EB1C53BF5200A81A14 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AutoLayout; + productName = AutoLayout; + productReference = 53D6A5ED1C53BF5200A81A14 /* AutoLayout.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53D6A5E51C53BF5200A81A14 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53D6A5EC1C53BF5200A81A14 = { + CreatedOnToolsVersion = 7.2; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + }; + }; + }; + buildConfigurationList = 53D6A5E81C53BF5200A81A14 /* Build configuration list for PBXProject "AutoLayout" */; + compatibilityVersion = "Xcode 6.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ar, + ); + mainGroup = 53D6A5E41C53BF5200A81A14; + productRefGroup = 53D6A5EE1C53BF5200A81A14 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53D6A5EC1C53BF5200A81A14 /* AutoLayout */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53D6A5EB1C53BF5200A81A14 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53D6A5FD1C53BF5200A81A14 /* LaunchScreen.storyboard in Resources */, + 53D6A5FA1C53BF5200A81A14 /* Assets.xcassets in Resources */, + 53D6A5F81C53BF5200A81A14 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53D6A5E91C53BF5200A81A14 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53EDF40F1C5D66AA009F91EA /* UIViewController+Constraint.swift in Sources */, + 53EDF40A1C5D64C1009F91EA /* UIStackView+addView.swift in Sources */, + 53D6A5F31C53BF5200A81A14 /* MasterViewController.swift in Sources */, + 53358D6F1C80F0B100C1842A /* LayoutGuideController.swift in Sources */, + 5319D0191CA6E8C1009E4AFA /* AdaptiveViewController.swift in Sources */, + 53EDF4081C5D5C78009F91EA /* StackViewController.swift in Sources */, + 535078741CBAD4D400700816 /* RTLViewController.swift in Sources */, + 5329F1161C79008300A35954 /* LayoutAnchorController.swift in Sources */, + 53EDF40C1C5D6641009F91EA /* UIViewController+addView.swift in Sources */, + 5362E7F81C53F1B200DAA88B /* CenterAlignViewController.swift in Sources */, + 53D6A5F11C53BF5200A81A14 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53D6A5F61C53BF5200A81A14 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53D6A5F71C53BF5200A81A14 /* Base */, + 535078751CBADA0C00700816 /* ar */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53D6A5FB1C53BF5200A81A14 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53D6A5FC1C53BF5200A81A14 /* Base */, + 535078761CBADA0C00700816 /* ar */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53D6A5FF1C53BF5200A81A14 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53D6A6001C53BF5200A81A14 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53D6A6021C53BF5200A81A14 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AutoLayout/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AutoLayout; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53D6A6031C53BF5200A81A14 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = AutoLayout/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.AutoLayout; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53D6A5E81C53BF5200A81A14 /* Build configuration list for PBXProject "AutoLayout" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D6A5FF1C53BF5200A81A14 /* Debug */, + 53D6A6001C53BF5200A81A14 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53D6A6011C53BF5200A81A14 /* Build configuration list for PBXNativeTarget "AutoLayout" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D6A6021C53BF5200A81A14 /* Debug */, + 53D6A6031C53BF5200A81A14 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53D6A5E51C53BF5200A81A14 /* Project object */; +} diff --git a/AutoLayout/AutoLayout/AdaptiveViewController.swift b/AutoLayout/AutoLayout/AdaptiveViewController.swift new file mode 100644 index 0000000..e96eb39 --- /dev/null +++ b/AutoLayout/AutoLayout/AdaptiveViewController.swift @@ -0,0 +1,181 @@ +// +// AdaptiveViewController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class AdaptiveViewController: UIViewController { + + let textLabel = UILabel() + let leadingGuide = UILayoutGuide() + let redButton = UIButton(type: .custom) + let middleGuide = UILayoutGuide() + let greenButton = UIButton(type: .custom) + let trailingGuide = UILayoutGuide() + + var compactConstraints = [NSLayoutConstraint]() + var regularConstraints = [NSLayoutConstraint]() + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + setupConstraints() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass { + enableConstraintsForWidth(traitCollection.horizontalSizeClass) + } + } + + private func setupViews() { + + textLabel.text = "Vertically align for compact widths" + textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.numberOfLines = 0 + textLabel.textAlignment = .center + textLabel.textColor = .gray + + redButton.translatesAutoresizingMaskIntoConstraints = false + redButton.setTitle("No don't do it", for: UIControl.State()) + let redImage = UIImage(named: "redButton") + redButton.setBackgroundImage(redImage, for: UIControl.State()) + redButton.contentEdgeInsets = UIEdgeInsets.init(top: 8, left: 16, bottom: 8, right: 16) + let noAction = #selector(noAction(_:)) + redButton.addTarget(self, action: noAction, for: .touchUpInside) + + greenButton.translatesAutoresizingMaskIntoConstraints = false + greenButton.setTitle("Start the Countdown!!!", for: UIControl.State()) + let greenImage = UIImage(named: "greenButton") + greenButton.setBackgroundImage(greenImage, for: UIControl.State()) + greenButton.contentEdgeInsets = UIEdgeInsets.init(top: 8, left: 16, bottom: 8, right: 16) + let yesAction = #selector(yesAction(_:)) + greenButton.addTarget(self, action: yesAction, for: .touchUpInside) + + view.addSubview(textLabel) + view.addSubview(redButton) + view.addSubview(greenButton) + view.addLayoutGuide(leadingGuide) + view.addLayoutGuide(middleGuide) + view.addLayoutGuide(trailingGuide) + } + + private var firstTime = true + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + if firstTime { + firstTime = false + enableConstraintsForWidth(traitCollection.horizontalSizeClass) + } + } + + private func setupConstraints() { + + // ========================================= + // common constraints, activate immediately. + // ========================================= + + let contentGuide = view.readableContentGuide + textLabel.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor).isActive = true + textLabel.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor).isActive = true + textLabel.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8.0).isActive = true + + redButton.topAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 8.0).isActive = true + redButton.widthAnchor.constraint(equalTo: greenButton.widthAnchor).isActive = true + + leadingGuide.widthAnchor.constraint(equalTo: middleGuide.widthAnchor).isActive = true + leadingGuide.widthAnchor.constraint(equalTo: trailingGuide.widthAnchor).isActive = true + + view.leadingAnchor.constraint(equalTo: leadingGuide.leadingAnchor).isActive = true + trailingGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + + // ========================================= + // regular width constraints + // ========================================= + + // = |---------------------------------------------------------| = + // = | ************ | = + // = | *textLabel * | = + // = | ************ | = + // = |+++++++++++************+++++++++++************+++++++++++| = + // = |+ leading +* red *+ middle +* green *+ trailing+| = + // = |+ guide +* button *+ guide +* button *+ guide +| = + // = |+++++++++++************+++++++++++************+++++++++++| = + + regularConstraints.append(leadingGuide.trailingAnchor.constraint(equalTo: redButton.leadingAnchor)) + regularConstraints.append(redButton.trailingAnchor.constraint(equalTo: middleGuide.leadingAnchor)) + regularConstraints.append(middleGuide.trailingAnchor.constraint(equalTo: greenButton.leadingAnchor)) + regularConstraints.append(greenButton.trailingAnchor.constraint(equalTo: trailingGuide.leadingAnchor)) + regularConstraints.append(greenButton.topAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 8.0)) + + // ========================================= + // compact width constraints + // ========================================= + + // = |---------------------------------------------------------| = + // = | ************ | = + // = | *textLabel * | = + // = | ************ | = + // = | ************ | = + // = | * red * | = + // = | * button * | = + // = | ************ | = + // = | ************ | = + // = | * green * | = + // = | * button * | = + // = | ************ | = + // = |+++++++++++************+++++++++++************+++++++++++| = + + compactConstraints.append(redButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)) + compactConstraints.append(greenButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)) + compactConstraints.append(greenButton.topAnchor.constraint(equalTo: redButton.bottomAnchor, constant: 8.0)) + } + + private func enableConstraintsForWidth(_ horizontalSizeClass: UIUserInterfaceSizeClass) { + if horizontalSizeClass == .regular { + NSLayoutConstraint.deactivate(compactConstraints) + NSLayoutConstraint.activate(regularConstraints) + } else { + NSLayoutConstraint.deactivate(regularConstraints) + NSLayoutConstraint.activate(compactConstraints) + } + } + + @objc func noAction(_ sender: UIButton) { + print("No") + } + + @objc func yesAction(_ sender: UIButton) { + print("Yes") + } +} diff --git a/AutoLayout/AutoLayout/AppDelegate.swift b/AutoLayout/AutoLayout/AppDelegate.swift new file mode 100644 index 0000000..828bcfd --- /dev/null +++ b/AutoLayout/AutoLayout/AppDelegate.swift @@ -0,0 +1,51 @@ +// +// AppDelegate.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + let splitViewController = self.window!.rootViewController as! UISplitViewController + splitViewController.delegate = self + return true + } + + func splitViewController(_ svc: UISplitViewController, shouldHide vc: UIViewController, in orientation: UIInterfaceOrientation) -> Bool { + return false + } +} + diff --git a/AutoLayout/AutoLayout/Assets.xcassets/AppIcon.appiconset/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Buttons/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/Contents.json new file mode 100644 index 0000000..30dee8d --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "green.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "stretch", + "width" : 1 + }, + "cap-insets" : { + "right" : 20, + "left" : 20 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/green.pdf b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/green.pdf new file mode 100644 index 0000000..b3fa12c Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/greenButton.imageset/green.pdf differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/Contents.json new file mode 100644 index 0000000..23f07a9 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "red.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "stretch", + "width" : 1 + }, + "cap-insets" : { + "right" : 20, + "left" : 20 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/red.pdf b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/red.pdf new file mode 100644 index 0000000..a38672b Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Buttons/redButton.imageset/red.pdf differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/Contents.json new file mode 100644 index 0000000..e338ea6 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/Contents.json @@ -0,0 +1,114 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "heart100.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "heart200.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "heart300.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "scale" : "1x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "2x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "3x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "1x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "2x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "3x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "filename" : "heart120.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "heart240.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "heart360.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "height-class" : "regular" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "height-class" : "regular" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "width-class" : "regular" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "width-class" : "regular" + }, + { + "idiom" : "ipad", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart100.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart100.png new file mode 100644 index 0000000..d6be769 Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart100.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart120.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart120.png new file mode 100644 index 0000000..3dd922e Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart120.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart200.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart200.png new file mode 100644 index 0000000..932019f Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart200.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart240.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart240.png new file mode 100644 index 0000000..1ecead5 Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart240.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart300.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart300.png new file mode 100644 index 0000000..c24ae62 Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart300.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart360.png b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart360.png new file mode 100644 index 0000000..b127587 Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Heart.imageset/heart360.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/Contents.json b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/Contents.json new file mode 100644 index 0000000..edc4546 --- /dev/null +++ b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/Contents.json @@ -0,0 +1,74 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star100.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "star200.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "star300.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "scale" : "1x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "2x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "3x", + "height-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "1x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "2x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "scale" : "3x", + "width-class" : "regular" + }, + { + "idiom" : "universal", + "filename" : "star120.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "star240.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "star360.png", + "width-class" : "regular", + "height-class" : "regular", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star100.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star100.png new file mode 100644 index 0000000..4965255 Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star100.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star120.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star120.png new file mode 100644 index 0000000..dd1860f Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star120.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star200.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star200.png new file mode 100644 index 0000000..49311bc Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star200.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star240.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star240.png new file mode 100644 index 0000000..3e956cc Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star240.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star300.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star300.png new file mode 100644 index 0000000..d46d41b Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star300.png differ diff --git a/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star360.png b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star360.png new file mode 100644 index 0000000..dc8514c Binary files /dev/null and b/AutoLayout/AutoLayout/Assets.xcassets/Star.imageset/star360.png differ diff --git a/AutoLayout/AutoLayout/Base.lproj/LaunchScreen.storyboard b/AutoLayout/AutoLayout/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..1fb311e --- /dev/null +++ b/AutoLayout/AutoLayout/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutoLayout/AutoLayout/Base.lproj/Main.storyboard b/AutoLayout/AutoLayout/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9d32cfb --- /dev/null +++ b/AutoLayout/AutoLayout/Base.lproj/Main.storyboard @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutoLayout/AutoLayout/CenterAlignViewController.swift b/AutoLayout/AutoLayout/CenterAlignViewController.swift new file mode 100644 index 0000000..af2f9df --- /dev/null +++ b/AutoLayout/AutoLayout/CenterAlignViewController.swift @@ -0,0 +1,74 @@ +// +// CenterAlignViewController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class CenterAlignViewController: UIViewController { + + var heartTop: UIImageView? + var starTop: UIImageView? + var starBottomLeft: UIImageView? + var heartBottom: UIImageView? + var starBottomRight: UIImageView? + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + } + + func setupViews() { + heartTop = addImageViewForImageNamed("Heart") + starTop = addImageViewForImageNamed("Star") + starBottomLeft = addImageViewForImageNamed("Star") + heartBottom = addImageViewForImageNamed("Heart") + starBottomRight = addImageViewForImageNamed("Star") + setupConstraints() + } + + func setupConstraints() { + addConstraintFromView(heartTop, attribute: .centerY, multiplier: 0.667, identifier: "heartTop center Y") + addConstraintFromView(starTop, attribute: .centerY, multiplier: 0.667, identifier: "starTop center Y") + + addConstraintFromView(heartTop, attribute: .centerX, multiplier: 0.5, identifier: "heartTop center X") + addConstraintFromView(starTop, attribute: .centerX, multiplier: 1.5, identifier: "starTop center X") + + + addConstraintFromView(starBottomLeft, attribute: .centerY, multiplier: 1.333, identifier: "startBottomLeft center Y") + addConstraintFromView(heartBottom, attribute: .centerY, multiplier: 1.333, identifier: "heartBottom center Y") + addConstraintFromView(starBottomRight, attribute: .centerY, multiplier: 1.333, identifier: "starBottomRight center Y") + + addConstraintFromView(starBottomLeft, attribute: .centerX, multiplier: 0.333, identifier: "starBottomLeft center X") + addConstraintFromView(heartBottom, attribute: .centerX, multiplier: 1.0, identifier: "heartBottom center X") + addConstraintFromView(starBottomRight, attribute: .centerX, multiplier: 1.667, identifier: "starBottomRight center X") + } +} diff --git a/AutoLayout/AutoLayout/Info.plist b/AutoLayout/AutoLayout/Info.plist new file mode 100644 index 0000000..c6233b9 --- /dev/null +++ b/AutoLayout/AutoLayout/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.5 + CFBundleSignature + ???? + CFBundleVersion + 5 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AutoLayout/AutoLayout/LayoutAnchorController.swift b/AutoLayout/AutoLayout/LayoutAnchorController.swift new file mode 100644 index 0000000..455e510 --- /dev/null +++ b/AutoLayout/AutoLayout/LayoutAnchorController.swift @@ -0,0 +1,118 @@ +// +// LayoutAnchorController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class LayoutAnchorController: UIViewController { + + let stackView = UIStackView() + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + } + + func setupViews() { + + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.distribution = .equalSpacing + view.addSubview(stackView) + + stackView.addImageViewForImage("Heart") + stackView.addImageViewForImage("Star") + stackView.addImageViewForImage("Heart") + +// Constraints to pin the stack view to the leading and trailing +// margins of the superview and below the top layout guide. + +// The code below shows three different ways to achieve this: + +// 1. Using the NSLayoutConstraint class method to create +// each individual constraint. The most verbose of the +// three approaches. +// +// NSLayoutConstraint(item: stackView, +// attribute: .Leading, +// relatedBy: .Equal, +// toItem: view, +// attribute: .LeadingMargin, +// multiplier: 1, +// constant: 0).active = true +// +// NSLayoutConstraint(item: stackView, +// attribute: .Trailing, +// relatedBy: .Equal, +// toItem: view, +// attribute: .TrailingMargin, +// multiplier: 1, +// constant: 0).active = true +// +// NSLayoutConstraint(item: stackView, +// attribute: .Top, +// relatedBy: .Equal, +// toItem: topLayoutGuide, +// attribute: .Bottom, +// multiplier: 1, +// constant: 8.0).active = true + +// 2. Using the Visual Format Language to add both constraints +// in one go. Shorter but still not very readable. + +// let views: [String: AnyObject] = +// ["stackView" : stackView, +// "topLayoutGuide" : topLayoutGuide] +// +// let h = NSLayoutConstraint.constraintsWithVisualFormat( +// "|-[stackView]-|", +// options: [], +// metrics: nil, +// views: views) +// NSLayoutConstraint.activateConstraints(h) +// +// let v = NSLayoutConstraint.constraintsWithVisualFormat( +// "V:|[topLayoutGuide]-[stackView]", +// options: [], +// metrics: nil, +// views: views) +// NSLayoutConstraint.activateConstraints(v) + +// 3. Using layout anchors - by far the easiest method but requires +// iOS 9. + + let margins = view.layoutMarginsGuide + + stackView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true + stackView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true + stackView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8.0).isActive = true + } +} diff --git a/AutoLayout/AutoLayout/LayoutGuideController.swift b/AutoLayout/AutoLayout/LayoutGuideController.swift new file mode 100644 index 0000000..b092cd7 --- /dev/null +++ b/AutoLayout/AutoLayout/LayoutGuideController.swift @@ -0,0 +1,129 @@ +// +// LayoutGuideController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LayoutGuideController: UIViewController { + // Use layout guides as an alternative to spacer views + // The two buttons will be placed between the view margins + // with equal spacing between the buttons and the margins + // so that the width of the three guides is equal. + + // = |+++++++++++************+++++++++++************+++++++++++| = + // = |+ leading +* no *+ middle +* yes *+ trailing+| = + // = |+ guide +* button *+ guide +* button *+ guide +| = + // = |+++++++++++************+++++++++++************+++++++++++| = + + let leadingGuide = UILayoutGuide() + let noButton = UIButton(type: .custom) + let middleGuide = UILayoutGuide() + let yesButton = UIButton(type: .custom) + let trailingGuide = UILayoutGuide() + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + setupConstraints() + } + + private func setupViews() { + // Configure the buttons and add them to the superview + + noButton.translatesAutoresizingMaskIntoConstraints = false + noButton.setTitle("No", for: .normal) + let redImage = UIImage(named: "redButton") + noButton.setBackgroundImage(redImage, for: .normal) + noButton.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) + noButton.addTarget(self, action: #selector(LayoutGuideController.noThanks(_:)), for: .touchUpInside) + + yesButton.translatesAutoresizingMaskIntoConstraints = false + yesButton.setTitle("Yes please!", for: .normal) + let greenImage = UIImage(named: "greenButton") + yesButton.setBackgroundImage(greenImage, for: .normal) + yesButton.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) + yesButton.addTarget(self, action: #selector(LayoutGuideController.yesPlease(_:)), for: .touchUpInside) + + view.addSubview(noButton) + view.addSubview(yesButton) + + // Add the layout guides to the view + // Note that the guides are not part of the + // view hierarchy + + view.addLayoutGuide(leadingGuide) + view.addLayoutGuide(middleGuide) + view.addLayoutGuide(trailingGuide) + } + + private func setupConstraints() { + // The views are spaced relative to the margings of + // the superview. To space the views relative to the + // edges of the super view replace "margins" with + // "view" in the constraints below + + let margins = view.layoutMarginsGuide + NSLayoutConstraint.activate([ + // leading to trailing constraints + // working from left to right + + margins.leadingAnchor.constraint(equalTo: leadingGuide.leadingAnchor), + leadingGuide.trailingAnchor.constraint(equalTo: noButton.leadingAnchor), + noButton.trailingAnchor.constraint(equalTo: middleGuide.leadingAnchor), + middleGuide.trailingAnchor.constraint(equalTo: yesButton.leadingAnchor), + yesButton.trailingAnchor.constraint(equalTo: trailingGuide.leadingAnchor), + trailingGuide.trailingAnchor.constraint(equalTo: margins.trailingAnchor), + + // The buttons should have the same width + noButton.widthAnchor.constraint(equalTo: yesButton.widthAnchor), + + // The guides should have the same width + leadingGuide.widthAnchor.constraint(equalTo: middleGuide.widthAnchor), + leadingGuide.widthAnchor.constraint(equalTo: trailingGuide.widthAnchor), + + // Center everything vertically in the super view + leadingGuide.centerYAnchor.constraint(equalTo: view.centerYAnchor), + middleGuide.centerYAnchor.constraint(equalTo: view.centerYAnchor), + trailingGuide.centerYAnchor.constraint(equalTo: view.centerYAnchor), + noButton.centerYAnchor.constraint(equalTo: view.centerYAnchor), + yesButton.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + @objc private func noThanks(_ sender: UIButton) { + print("No thanks!") + } + + @objc private func yesPlease(_ sender: UIButton) { + print("Yes please!") + } +} diff --git a/AutoLayout/AutoLayout/MasterViewController.swift b/AutoLayout/AutoLayout/MasterViewController.swift new file mode 100644 index 0000000..93cf486 --- /dev/null +++ b/AutoLayout/AutoLayout/MasterViewController.swift @@ -0,0 +1,49 @@ +// +// MasterViewController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class MasterViewController: UITableViewController { + + override func viewWillAppear(_ animated: Bool) { + self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed + super.viewWillAppear(animated) + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if let controller = (segue.destination as! UINavigationController).topViewController { + controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem + controller.navigationItem.leftItemsSupplementBackButton = true + } + } +} diff --git a/AutoLayout/AutoLayout/RTLViewController.swift b/AutoLayout/AutoLayout/RTLViewController.swift new file mode 100644 index 0000000..a40d90f --- /dev/null +++ b/AutoLayout/AutoLayout/RTLViewController.swift @@ -0,0 +1,69 @@ +// +// RTLViewController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class RTLViewController: UIViewController { + + var cherryLabel = UILabel() + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + setupConstraints() + setupSemanticLayout() + } + + private func setupViews() { + cherryLabel.text = "🍒🍒🍒" + cherryLabel.backgroundColor = .green + cherryLabel.textAlignment = .right + view.addSubview(cherryLabel) + } + + private func setupConstraints() { + let margins = view.layoutMarginsGuide + cherryLabel.translatesAutoresizingMaskIntoConstraints = false + cherryLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true + cherryLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true + cherryLabel.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 20.0).isActive = true + } + + private func setupSemanticLayout() { + let attribute = view.semanticContentAttribute + let layoutDirection = UIView.userInterfaceLayoutDirection(for: attribute) + if layoutDirection == .rightToLeft { + cherryLabel.textAlignment = .left + } + } +} diff --git a/AutoLayout/AutoLayout/StackViewController.swift b/AutoLayout/AutoLayout/StackViewController.swift new file mode 100644 index 0000000..6fd8b44 --- /dev/null +++ b/AutoLayout/AutoLayout/StackViewController.swift @@ -0,0 +1,82 @@ +// +// StackViewController.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class StackViewController: UIViewController { + + var heartTop: UIImageView? + var starTop: UIImageView? + var starBottomLeft: UIImageView? + var heartBottom: UIImageView? + var starBottomRight: UIImageView? + + let topStackView = UIStackView() + let bottomStackView = UIStackView() + + override func viewDidLoad() { + super.viewDidLoad() + setupViews() + } + + func setupViews() { + + topStackView.translatesAutoresizingMaskIntoConstraints = false + topStackView.distribution = .equalSpacing + view.addSubview(topStackView) + + bottomStackView.translatesAutoresizingMaskIntoConstraints = false + bottomStackView.distribution = .equalSpacing + view.addSubview(bottomStackView) + + heartTop = topStackView.addImageViewForImage("Heart") + starTop = topStackView.addImageViewForImage("Star") + + starBottomLeft = bottomStackView.addImageViewForImage("Star") + heartBottom = bottomStackView.addImageViewForImage("Heart") + starBottomRight = bottomStackView.addImageViewForImage("Star") + + // Set the vertical position of each stack view + addConstraintFromView(topStackView, attribute: .centerY, multiplier: 0.667, identifier: "topSV center Y") + addConstraintFromView(bottomStackView, attribute: .centerY, multiplier: 1.333, identifier: "bottomSV center Y") + + // Center both stack views + addConstraintFromView(topStackView, attribute: .centerX, multiplier: 1.0, identifier: "topSv center X") + addConstraintFromView(bottomStackView, attribute: .centerX, multiplier: 1.0, identifier: "bottomSV center X") + + // Fix the width of the stack view by setting the center + // of the left image. + addConstraintFromView(heartTop, attribute: .centerX, multiplier: 0.5, identifier: "heartTop center X") + addConstraintFromView(starBottomLeft, attribute: .centerX, multiplier: 0.333, identifier: "starBottomLeft center X") + } +} diff --git a/AutoLayout/AutoLayout/UIStackView+addView.swift b/AutoLayout/AutoLayout/UIStackView+addView.swift new file mode 100644 index 0000000..e34308b --- /dev/null +++ b/AutoLayout/AutoLayout/UIStackView+addView.swift @@ -0,0 +1,63 @@ +// +// UIStackView+addImage.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/** + A UIStackView extension for adding views to a stack view + */ + +extension UIStackView { + + /** + A convenience method to create a UIImageView and then + add it to the stack view. The UIImageView is created + from a UIImage using the name parameter. + + - Parameter name: A String which should match the name + of a valid image file in the application bundle or asset + catalog. + + - Returns: The newly created UIImageView or nil. + */ + + @discardableResult func addImageViewForImage(_ name: String) -> UIImageView? { + if let image = UIImage(named: name) { + let imageView = UIImageView(image: image) + imageView.translatesAutoresizingMaskIntoConstraints = false + addArrangedSubview(imageView) + return imageView + } + return nil + } +} diff --git a/AutoLayout/AutoLayout/UIViewController+Constraint.swift b/AutoLayout/AutoLayout/UIViewController+Constraint.swift new file mode 100644 index 0000000..8cb4f05 --- /dev/null +++ b/AutoLayout/AutoLayout/UIViewController+Constraint.swift @@ -0,0 +1,85 @@ +// +// UIViewController+Constraint.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/** + A UIViewController extension for adding constraints to the + view controller view. + */ + +extension UIViewController { + + /** + A convenience method to create and add a constraint + between a subview and the view of the view controller. + This method assumes the constraint uses the same + attribute for both views. + + For example, to horizontally center a view at + half way to the center of the view controller view: + + addConstraintFromView(myView, + attribute: .CenterX, + multiplier: 0.5, + identifier: "myView center X") + + - Note: This method does not add the subview to the + view hierarchy of the view controller. + + - Parameter subview: The subview of the view controller + from which to add the constraint. + + - Parameter attribute: The NSLayoutAttribute for both + the from and to item. + + - Parameter multipler: A CGFloat constant that multiplies + the attribute of the to item. + + - Parameter identifier: A String identifier to aid debugging. + */ + + func addConstraintFromView(_ subview: UIView?, attribute: NSLayoutConstraint.Attribute, multiplier: CGFloat, identifier: String) { + if let subview = subview { + let constraint = NSLayoutConstraint(item: subview, + attribute: attribute, + relatedBy: .equal, + toItem: view, + attribute: attribute, + multiplier: multiplier, + constant: 0) + constraint.identifier = identifier + view.addConstraint(constraint) + } + } +} diff --git a/AutoLayout/AutoLayout/UIViewController+addView.swift b/AutoLayout/AutoLayout/UIViewController+addView.swift new file mode 100644 index 0000000..1906c28 --- /dev/null +++ b/AutoLayout/AutoLayout/UIViewController+addView.swift @@ -0,0 +1,68 @@ +// +// UIViewController+addView.swift +// AutoLayout +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/** + A UIViewController extension for adding views to a view controller + */ + +extension UIViewController { + + /** + A convenience method to create a UIImageView and then + add it to the view controller view. The UIImageView is + created from a UIImage using the name parameter. + + - Note: The translatesAutoresizingMaskIntoConstraints + flag is set to false for the UIImageView. Make sure you + add sufficient constraint to fix the position. + + - Parameter name: A String which should match the name + of a valid image file in the application bundle or asset + catalog. + + - Returns: The newly created UIImageView or nil. + */ + + func addImageViewForImageNamed(_ name: String) -> UIImageView? { + if let image = UIImage(named: name) { + let imageView = UIImageView(image: image) + imageView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(imageView) + return imageView + } + return nil + } +} + diff --git a/AutoLayout/AutoLayout/ar.lproj/LaunchScreen.strings b/AutoLayout/AutoLayout/ar.lproj/LaunchScreen.strings new file mode 100644 index 0000000..50c7fb3 --- /dev/null +++ b/AutoLayout/AutoLayout/ar.lproj/LaunchScreen.strings @@ -0,0 +1,3 @@ + +/* Class = "UINavigationItem"; title = "Auto Layout"; ObjectID = "w7R-9T-cFr"; */ +"w7R-9T-cFr.title" = "Auto Layout"; diff --git a/AutoLayout/AutoLayout/ar.lproj/Main.strings b/AutoLayout/AutoLayout/ar.lproj/Main.strings new file mode 100644 index 0000000..b5577fc --- /dev/null +++ b/AutoLayout/AutoLayout/ar.lproj/Main.strings @@ -0,0 +1,78 @@ + +/* Class = "UINavigationItem"; title = "Layout Guides"; ObjectID = "2N3-RG-3wv"; */ +"2N3-RG-3wv.title" = "Layout Guides"; + +/* Class = "UINavigationItem"; title = "Right-to-Left Text"; ObjectID = "5f0-UM-BEy"; */ +"5f0-UM-BEy.title" = "Right-to-Left Text"; + +/* Class = "UILabel"; text = "Adaptive Constraints (Code)"; ObjectID = "6jd-Nf-je0"; */ +"6jd-Nf-je0.text" = "Adaptive Constraints (Code)"; + +/* Class = "UITableViewController"; title = "Master"; ObjectID = "7bK-jq-Zjz"; */ +"7bK-jq-Zjz.title" = "Master"; + +/* Class = "UILabel"; text = "The buttons should be arranged horizontallly for regular width"; ObjectID = "8Ox-yu-ipp"; */ +"8Ox-yu-ipp.text" = "The buttons should be arranged horizontallly for regular width"; + +/* Class = "UILabel"; text = "Center Alignment (IB)"; ObjectID = "Arm-wq-HPj"; */ +"Arm-wq-HPj.text" = "Center Alignment (IB)"; + +/* Class = "UILabel"; text = "Adaptive Constraints (StackView)"; ObjectID = "C32-Uh-N2Q"; */ +"C32-Uh-N2Q.text" = "Adaptive Constraints (StackView)"; + +/* Class = "UIViewController"; title = "Layout Guides"; ObjectID = "CNI-hu-MFk"; */ +"CNI-hu-MFk.title" = "Layout Guides"; + +/* Class = "UINavigationItem"; title = "Stack View"; ObjectID = "Igg-Oh-Iag"; */ +"Igg-Oh-Iag.title" = "Stack View"; + +/* Class = "UINavigationItem"; title = "Interface Builder"; ObjectID = "J4l-Ce-vy6"; */ +"J4l-Ce-vy6.title" = "Interface Builder"; + +/* Class = "UILabel"; text = "Center Alignment (Code)"; ObjectID = "Psd-1R-l88"; */ +"Psd-1R-l88.text" = "Center Alignment (Code)"; + +/* Class = "UILabel"; text = "Tomorrow"; ObjectID = "QHI-p4-xwb"; */ +"QHI-p4-xwb.text" = "يوم غد"; + +/* Class = "UINavigationController"; title = "Master"; ObjectID = "RMx-3f-FxP"; */ +"RMx-3f-FxP.title" = "Master"; + +/* Class = "UILabel"; text = "Layout Anchors"; ObjectID = "UuN-2A-3RZ"; */ +"UuN-2A-3RZ.text" = "Layout Anchors"; + +/* Class = "UINavigationItem"; title = "Layout Anchors"; ObjectID = "XlE-eb-7cw"; */ +"XlE-eb-7cw.title" = "Layout Anchors"; + +/* Class = "UINavigationItem"; title = "Auto Layout"; ObjectID = "Zdf-7t-Un8"; */ +"Zdf-7t-Un8.title" = "Auto Layout"; + +/* Class = "UIButton"; normalTitle = "No"; ObjectID = "b2a-MG-Gkh"; */ +"b2a-MG-Gkh.normalTitle" = "No"; + +/* Class = "UILabel"; text = "Today"; ObjectID = "fUe-le-V3b"; */ +"fUe-le-V3b.text" = "اليوم"; + +/* Class = "UILabel"; text = "Layout Guides"; ObjectID = "hPN-HB-hY7"; */ +"hPN-HB-hY7.text" = "Layout Guides"; + +/* Class = "UINavigationItem"; title = "Code Layout"; ObjectID = "iHn-Kl-LzN"; */ +"iHn-Kl-LzN.title" = "Code Layout"; + +/* Class = "UILabel"; text = "Yesterday"; ObjectID = "j9t-ce-jkS"; */ +"j9t-ce-jkS.text" = "اليوم السابق"; + +/* Class = "UIButton"; normalTitle = "Yes"; ObjectID = "jAq-dO-Gfh"; */ +"jAq-dO-Gfh.normalTitle" = "Yes"; + +/* Class = "UINavigationItem"; title = "Adaptive Constraints"; ObjectID = "jg5-Sy-S4h"; */ +"jg5-Sy-S4h.title" = "Adaptive Constraints"; + +/* Class = "UILabel"; text = "Right To Left Text Alignment"; ObjectID = "pte-Pw-YBO"; */ +"pte-Pw-YBO.text" = "Right To Left Text Alignment"; + +/* Class = "UINavigationItem"; title = "Adaptive Constraints"; ObjectID = "wSr-Jq-acf"; */ +"wSr-Jq-acf.title" = "Adaptive Constraints"; + +/* Class = "UILabel"; text = "Center Alignment (StackView)"; ObjectID = "ywh-s2-iBh"; */ +"ywh-s2-iBh.text" = "Center Alignment (StackView)"; diff --git a/AutoLayout/README.md b/AutoLayout/README.md new file mode 100644 index 0000000..42086b1 --- /dev/null +++ b/AutoLayout/README.md @@ -0,0 +1,30 @@ +### AutoLayout + +Auto Layout examples using Interface Builder and in code. + ++ Proportional spacing using Interface Builder ++ Proportional spacing using code ++ Proportional spacing using a stack view ++ Layout Anchors ++ Layout Guides as spacer views ++ Adaptive constraints using Interface Builder and code ++ Support for Right-To-Left languages such as Arabic (run with Arabic scheme) + +See the following posts further details: + ++ [Proportional Spacing with Auto Layout](https://useyourloaf.com/blog/proportional-spacing-with-auto-layout/) ++ [Adapting Images for Size Classes](https://useyourloaf.com/blog/adapting-images-for-size-classes/) ++ [Pain Free Constraints with Layout Anchors](https://useyourloaf.com/blog/pain-free-constraints-with-layout-anchors/) ++ [Goodbye Spacer Views Hello Layout Guides](https://useyourloaf.com/blog/goodbye-spacer-views-hello-layout-guides/) ++ [Adapting AutoLayout Without Interface Builder](https://useyourloaf.com/blog/adapting-auto-layout-without-interface-builder/) ++ [Natural Text Alignment for RTL Languages](https://useyourloaf.com/blog/natural-text-alignment-for-rtl-languages/) + +#### Version History + ++ Version 1.6 29 Jul 2016 Update for Xcode 8 and Swift 3 ++ Version 1.5 12 Apr 2016 Add example of RTL Language Support ++ Version 1.4 28 Mar 2016 Adapting constraints to size classes ++ Version 1.3 27 Feb 2016 Using layout guides to space views ++ Version 1.2 22 Feb 2016 Example of using layout anchors ++ Version 1.1 31 Jan 2016 Custom Asset catalog for size classes. ++ Version 1.0 15 Jan 2016 Initial Version diff --git a/BlastOff/BlastOff.xcodeproj/project.pbxproj b/BlastOff/BlastOff.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0f9f4af --- /dev/null +++ b/BlastOff/BlastOff.xcodeproj/project.pbxproj @@ -0,0 +1,349 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 53E5DCE32184979D001EE0D8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5DCE22184979D001EE0D8 /* AppDelegate.swift */; }; + 53E5DCE82184979D001EE0D8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53E5DCE62184979D001EE0D8 /* Main.storyboard */; }; + 53E5DCEA2184979E001EE0D8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53E5DCE92184979E001EE0D8 /* Assets.xcassets */; }; + 53E5DCED2184979E001EE0D8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53E5DCEB2184979E001EE0D8 /* LaunchScreen.storyboard */; }; + 53E5DCFE2184A8EF001EE0D8 /* LaunchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5DCFD2184A8EF001EE0D8 /* LaunchController.swift */; }; + 53E5DCFF2184A938001EE0D8 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 53E5DCF42184A728001EE0D8 /* Localizable.stringsdict */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53B0B511218750E800BBD609 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53E5DCDF2184979D001EE0D8 /* BlastOff.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlastOff.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53E5DCE22184979D001EE0D8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53E5DCE72184979D001EE0D8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53E5DCE92184979E001EE0D8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53E5DCEC2184979E001EE0D8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53E5DCEE2184979E001EE0D8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53E5DCF42184A728001EE0D8 /* Localizable.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = ""; }; + 53E5DCFD2184A8EF001EE0D8 /* LaunchController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53E5DCDC2184979D001EE0D8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53E5DCD62184979D001EE0D8 = { + isa = PBXGroup; + children = ( + 53B0B511218750E800BBD609 /* README.md */, + 53E5DCE12184979D001EE0D8 /* BlastOff */, + 53E5DCE02184979D001EE0D8 /* Products */, + ); + sourceTree = ""; + }; + 53E5DCE02184979D001EE0D8 /* Products */ = { + isa = PBXGroup; + children = ( + 53E5DCDF2184979D001EE0D8 /* BlastOff.app */, + ); + name = Products; + sourceTree = ""; + }; + 53E5DCE12184979D001EE0D8 /* BlastOff */ = { + isa = PBXGroup; + children = ( + 53E5DCE22184979D001EE0D8 /* AppDelegate.swift */, + 53E5DCFD2184A8EF001EE0D8 /* LaunchController.swift */, + 53E5DCF42184A728001EE0D8 /* Localizable.stringsdict */, + 53E5DCE62184979D001EE0D8 /* Main.storyboard */, + 53E5DCE92184979E001EE0D8 /* Assets.xcassets */, + 53E5DCEB2184979E001EE0D8 /* LaunchScreen.storyboard */, + 53E5DCEE2184979E001EE0D8 /* Info.plist */, + ); + path = BlastOff; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53E5DCDE2184979D001EE0D8 /* BlastOff */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53E5DCF12184979E001EE0D8 /* Build configuration list for PBXNativeTarget "BlastOff" */; + buildPhases = ( + 53E5DCDB2184979D001EE0D8 /* Sources */, + 53E5DCDC2184979D001EE0D8 /* Frameworks */, + 53E5DCDD2184979D001EE0D8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BlastOff; + productName = BlastOff; + productReference = 53E5DCDF2184979D001EE0D8 /* BlastOff.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53E5DCD72184979D001EE0D8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53E5DCDE2184979D001EE0D8 = { + CreatedOnToolsVersion = 10.0; + }; + }; + }; + buildConfigurationList = 53E5DCDA2184979D001EE0D8 /* Build configuration list for PBXProject "BlastOff" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53E5DCD62184979D001EE0D8; + productRefGroup = 53E5DCE02184979D001EE0D8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53E5DCDE2184979D001EE0D8 /* BlastOff */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53E5DCDD2184979D001EE0D8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E5DCED2184979E001EE0D8 /* LaunchScreen.storyboard in Resources */, + 53E5DCFF2184A938001EE0D8 /* Localizable.stringsdict in Resources */, + 53E5DCEA2184979E001EE0D8 /* Assets.xcassets in Resources */, + 53E5DCE82184979D001EE0D8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53E5DCDB2184979D001EE0D8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E5DCFE2184A8EF001EE0D8 /* LaunchController.swift in Sources */, + 53E5DCE32184979D001EE0D8 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53E5DCE62184979D001EE0D8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53E5DCE72184979D001EE0D8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53E5DCEB2184979E001EE0D8 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53E5DCEC2184979E001EE0D8 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53E5DCEF2184979E001EE0D8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53E5DCF02184979E001EE0D8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53E5DCF22184979E001EE0D8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = BlastOff/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.BlastOff; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53E5DCF32184979E001EE0D8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = BlastOff/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.BlastOff; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53E5DCDA2184979D001EE0D8 /* Build configuration list for PBXProject "BlastOff" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53E5DCEF2184979E001EE0D8 /* Debug */, + 53E5DCF02184979E001EE0D8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53E5DCF12184979E001EE0D8 /* Build configuration list for PBXNativeTarget "BlastOff" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53E5DCF22184979E001EE0D8 /* Debug */, + 53E5DCF32184979E001EE0D8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53E5DCD72184979D001EE0D8 /* Project object */; +} diff --git a/BlastOff/BlastOff/AppDelegate.swift b/BlastOff/BlastOff/AppDelegate.swift new file mode 100644 index 0000000..dd55aa9 --- /dev/null +++ b/BlastOff/BlastOff/AppDelegate.swift @@ -0,0 +1,35 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? +} diff --git a/BlastOff/BlastOff/Assets.xcassets/AppIcon.appiconset/Contents.json b/BlastOff/BlastOff/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/BlastOff/BlastOff/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BlastOff/BlastOff/Assets.xcassets/Contents.json b/BlastOff/BlastOff/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/BlastOff/BlastOff/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BlastOff/BlastOff/Base.lproj/LaunchScreen.storyboard b/BlastOff/BlastOff/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/BlastOff/BlastOff/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BlastOff/BlastOff/Base.lproj/Main.storyboard b/BlastOff/BlastOff/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d7b776c --- /dev/null +++ b/BlastOff/BlastOff/Base.lproj/Main.storyboard @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BlastOff/BlastOff/Info.plist b/BlastOff/BlastOff/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/BlastOff/BlastOff/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/BlastOff/BlastOff/LaunchController.swift b/BlastOff/BlastOff/LaunchController.swift new file mode 100644 index 0000000..51718d4 --- /dev/null +++ b/BlastOff/BlastOff/LaunchController.swift @@ -0,0 +1,48 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LaunchController: UIViewController { + + @IBOutlet private var abortButton: UIButton! + @IBOutlet private var startButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + } + + private func setupView() { + let startTitle = NSLocalizedString("Start", comment: "Start button") + startButton.setTitle(startTitle, for: .normal) + + let abortTitle = NSLocalizedString("Abort", comment: "Abort button") + abortButton.setTitle(abortTitle, for: .normal) + } +} diff --git a/BlastOff/BlastOff/Localizable.stringsdict b/BlastOff/BlastOff/Localizable.stringsdict new file mode 100755 index 0000000..f2f6b22 --- /dev/null +++ b/BlastOff/BlastOff/Localizable.stringsdict @@ -0,0 +1,30 @@ + + + + + Abort + + NSStringVariableWidthRuleType + + 20 + Abort + 25 + Abort Launch + 50 + Abort Launch Sequence + + + Start + + NSStringVariableWidthRuleType + + 20 + Start + 25 + Start Countdown + 50 + Start Launch Countdown + + + + diff --git a/BlastOff/README.md b/BlastOff/README.md new file mode 100644 index 0000000..8526a74 --- /dev/null +++ b/BlastOff/README.md @@ -0,0 +1,7 @@ +# Variable Width Strings + +An example of using a **localization strings dictionary** to create variable width strings. A `UILabel` or `UIButton` will automatically show the best string from the dictionary for the available screen width. + +For further details see the following blog post: + ++ [Variable Width Strings](https://useyourloaf.com/blog/variable-width-strings/) diff --git a/Buttons/Buttons.xcodeproj/project.pbxproj b/Buttons/Buttons.xcodeproj/project.pbxproj new file mode 100644 index 0000000..587fde8 --- /dev/null +++ b/Buttons/Buttons.xcodeproj/project.pbxproj @@ -0,0 +1,325 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5323B0B81C88D97300B183DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5323B0B71C88D97300B183DD /* AppDelegate.swift */; }; + 5323B0BA1C88D97300B183DD /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5323B0B91C88D97300B183DD /* ViewController.swift */; }; + 5323B0BD1C88D97300B183DD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5323B0BB1C88D97300B183DD /* Main.storyboard */; }; + 5323B0BF1C88D97300B183DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5323B0BE1C88D97300B183DD /* Assets.xcassets */; }; + 5323B0C21C88D97300B183DD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5323B0C01C88D97300B183DD /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5323B0B41C88D97300B183DD /* Buttons.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Buttons.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5323B0B71C88D97300B183DD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5323B0B91C88D97300B183DD /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 5323B0BC1C88D97300B183DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5323B0BE1C88D97300B183DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5323B0C11C88D97300B183DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5323B0C31C88D97300B183DD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5323B0B11C88D97300B183DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5323B0AB1C88D97300B183DD = { + isa = PBXGroup; + children = ( + 5323B0B61C88D97300B183DD /* Buttons */, + 5323B0B51C88D97300B183DD /* Products */, + ); + sourceTree = ""; + }; + 5323B0B51C88D97300B183DD /* Products */ = { + isa = PBXGroup; + children = ( + 5323B0B41C88D97300B183DD /* Buttons.app */, + ); + name = Products; + sourceTree = ""; + }; + 5323B0B61C88D97300B183DD /* Buttons */ = { + isa = PBXGroup; + children = ( + 5323B0B71C88D97300B183DD /* AppDelegate.swift */, + 5323B0B91C88D97300B183DD /* ViewController.swift */, + 5323B0BB1C88D97300B183DD /* Main.storyboard */, + 5323B0BE1C88D97300B183DD /* Assets.xcassets */, + 5323B0C01C88D97300B183DD /* LaunchScreen.storyboard */, + 5323B0C31C88D97300B183DD /* Info.plist */, + ); + path = Buttons; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5323B0B31C88D97300B183DD /* Buttons */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5323B0C61C88D97300B183DD /* Build configuration list for PBXNativeTarget "Buttons" */; + buildPhases = ( + 5323B0B01C88D97300B183DD /* Sources */, + 5323B0B11C88D97300B183DD /* Frameworks */, + 5323B0B21C88D97300B183DD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Buttons; + productName = Buttons; + productReference = 5323B0B41C88D97300B183DD /* Buttons.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5323B0AC1C88D97300B183DD /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5323B0B31C88D97300B183DD = { + CreatedOnToolsVersion = 7.2.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 0810; + }; + }; + }; + buildConfigurationList = 5323B0AF1C88D97300B183DD /* Build configuration list for PBXProject "Buttons" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5323B0AB1C88D97300B183DD; + productRefGroup = 5323B0B51C88D97300B183DD /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5323B0B31C88D97300B183DD /* Buttons */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5323B0B21C88D97300B183DD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5323B0C21C88D97300B183DD /* LaunchScreen.storyboard in Resources */, + 5323B0BF1C88D97300B183DD /* Assets.xcassets in Resources */, + 5323B0BD1C88D97300B183DD /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5323B0B01C88D97300B183DD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5323B0BA1C88D97300B183DD /* ViewController.swift in Sources */, + 5323B0B81C88D97300B183DD /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5323B0BB1C88D97300B183DD /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5323B0BC1C88D97300B183DD /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5323B0C01C88D97300B183DD /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5323B0C11C88D97300B183DD /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5323B0C41C88D97300B183DD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5323B0C51C88D97300B183DD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5323B0C71C88D97300B183DD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Buttons/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Buttons; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5323B0C81C88D97300B183DD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Buttons/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Buttons; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5323B0AF1C88D97300B183DD /* Build configuration list for PBXProject "Buttons" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5323B0C41C88D97300B183DD /* Debug */, + 5323B0C51C88D97300B183DD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5323B0C61C88D97300B183DD /* Build configuration list for PBXNativeTarget "Buttons" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5323B0C71C88D97300B183DD /* Debug */, + 5323B0C81C88D97300B183DD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5323B0AC1C88D97300B183DD /* Project object */; +} diff --git a/Buttons/Buttons/AppDelegate.swift b/Buttons/Buttons/AppDelegate.swift new file mode 100644 index 0000000..8bee4c3 --- /dev/null +++ b/Buttons/Buttons/AppDelegate.swift @@ -0,0 +1,41 @@ +// +// AppDelegate.swift +// Buttons +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? +} + diff --git a/Buttons/Buttons/Assets.xcassets/AppIcon.appiconset/Contents.json b/Buttons/Buttons/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/Contents.json new file mode 100644 index 0000000..70fd5a2 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "border.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/border.pdf b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/border.pdf new file mode 100644 index 0000000..0b798de Binary files /dev/null and b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedBorder.imageset/border.pdf differ diff --git a/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/Contents.json new file mode 100644 index 0000000..3168b55 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "filled.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/filled.pdf b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/filled.pdf new file mode 100644 index 0000000..bec3080 Binary files /dev/null and b/Buttons/Buttons/Assets.xcassets/Button Images - No Slicing/unslicedFill.imageset/filled.pdf differ diff --git a/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/Contents.json new file mode 100644 index 0000000..132fee5 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/Contents.json @@ -0,0 +1,29 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "border.pdf", + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "stretch", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 10, + "top" : 10, + "right" : 10, + "left" : 10 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/border.pdf b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/border.pdf new file mode 100644 index 0000000..0b798de Binary files /dev/null and b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedBorderTemplate.imageset/border.pdf differ diff --git a/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/Contents.json b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/Contents.json new file mode 100644 index 0000000..b2cf9b2 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/Contents.json @@ -0,0 +1,29 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "filled.pdf", + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "stretch", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 10, + "top" : 10, + "right" : 10, + "left" : 10 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/filled.pdf b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/filled.pdf new file mode 100644 index 0000000..bec3080 Binary files /dev/null and b/Buttons/Buttons/Assets.xcassets/Button Templates - Sliced/slicedFillTemplate.imageset/filled.pdf differ diff --git a/Buttons/Buttons/Assets.xcassets/Contents.json b/Buttons/Buttons/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Buttons/Buttons/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Buttons/Buttons/Base.lproj/LaunchScreen.storyboard b/Buttons/Buttons/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..548dc01 --- /dev/null +++ b/Buttons/Buttons/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Buttons/Buttons/Base.lproj/Main.storyboard b/Buttons/Buttons/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f5830ed --- /dev/null +++ b/Buttons/Buttons/Base.lproj/Main.storyboard @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Buttons/Buttons/Info.plist b/Buttons/Buttons/Info.plist new file mode 100644 index 0000000..40c6215 --- /dev/null +++ b/Buttons/Buttons/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Buttons/Buttons/ViewController.swift b/Buttons/Buttons/ViewController.swift new file mode 100644 index 0000000..dac117a --- /dev/null +++ b/Buttons/Buttons/ViewController.swift @@ -0,0 +1,68 @@ +// +// ViewController.swift +// Buttons +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class ViewController: UIViewController { + + @IBOutlet weak var stackView: UIStackView! + + override func viewDidLoad() { + super.viewDidLoad() + + // Create a custom button and set title label style + + let orangeButton = UIButton(type: .custom) + orangeButton.setTitle("Orange", for: .normal) + orangeButton.setTitleColor(.orange, for: .normal) + orangeButton.setTitleColor(.white, for: .highlighted) + orangeButton.titleLabel?.font = UIFont.systemFont(ofSize: 14) + orangeButton.contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) + + // Get the pre-sliced template images direct from the + // asset catalog for the default and hightlighted states + + let slicedBorderTemplate = UIImage(named: "slicedBorderTemplate") + let slicedFillTemplate = UIImage(named: "slicedFillTemplate") + + orangeButton.setBackgroundImage(slicedBorderTemplate, for: .normal) + orangeButton.setBackgroundImage(slicedFillTemplate, for: .highlighted) + + // The tintColor controls the colour used by the template images + // Defaults to inherited value + + orangeButton.tintColor = .orange + + stackView.addArrangedSubview(orangeButton) + } +} diff --git a/Container/Container-SB/Container.xcodeproj/project.pbxproj b/Container/Container-SB/Container.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f7d1a57 --- /dev/null +++ b/Container/Container-SB/Container.xcodeproj/project.pbxproj @@ -0,0 +1,539 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 534452FA1E61BA1F00649AF9 /* LocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534452F91E61BA1F00649AF9 /* LocationTests.swift */; }; + 534452FE1E61DF6200649AF9 /* locations.plist in Resources */ = {isa = PBXBuildFile; fileRef = 534452FD1E61DF6100649AF9 /* locations.plist */; }; + 5367B24C1E608B79001744C8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B24B1E608B79001744C8 /* AppDelegate.swift */; }; + 5367B2511E608B79001744C8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5367B24F1E608B79001744C8 /* Main.storyboard */; }; + 5367B2531E608B79001744C8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5367B2521E608B79001744C8 /* Assets.xcassets */; }; + 5367B2561E608B79001744C8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */; }; + 5367B25E1E608BE4001744C8 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B25D1E608BE4001744C8 /* MasterViewController.swift */; }; + 5367B2601E60A129001744C8 /* LocationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */; }; + 5367B2621E60A140001744C8 /* LocationDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2611E60A140001744C8 /* LocationDataSource.swift */; }; + 5367B2641E60A1A9001744C8 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2631E60A1A9001744C8 /* MapViewController.swift */; }; + 5367B2691E60A3C3001744C8 /* LocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2681E60A3C3001744C8 /* LocationCell.swift */; }; + 5367B26B1E60A5C6001744C8 /* ReusableIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */; }; + 5367B26E1E60A641001744C8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */; }; + 5367B2721E60A694001744C8 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2711E60A694001744C8 /* Location.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 534452F41E61B9E600649AF9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5367B2401E608B79001744C8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5367B2471E608B79001744C8; + remoteInfo = Container; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ContainerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 534452F31E61B9E600649AF9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 534452F91E61BA1F00649AF9 /* LocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTests.swift; sourceTree = ""; }; + 534452FD1E61DF6100649AF9 /* locations.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = locations.plist; sourceTree = ""; }; + 534452FF1E6216A100649AF9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; + 5367B2481E608B79001744C8 /* Container.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Container.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5367B24B1E608B79001744C8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5367B2501E608B79001744C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5367B2521E608B79001744C8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5367B2551E608B79001744C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5367B2571E608B79001744C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5367B25D1E608BE4001744C8 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTableViewController.swift; sourceTree = ""; }; + 5367B2611E60A140001744C8 /* LocationDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationDataSource.swift; sourceTree = ""; }; + 5367B2631E60A1A9001744C8 /* MapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + 5367B2661E60A29E001744C8 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + 5367B2681E60A3C3001744C8 /* LocationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationCell.swift; sourceTree = ""; }; + 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableIdentifier.swift; sourceTree = ""; }; + 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; + 5367B2711E60A694001744C8 /* Location.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 534452EC1E61B9E600649AF9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2451E608B79001744C8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 534452F01E61B9E600649AF9 /* ContainerTests */ = { + isa = PBXGroup; + children = ( + 534452F91E61BA1F00649AF9 /* LocationTests.swift */, + 534452F31E61B9E600649AF9 /* Info.plist */, + ); + path = ContainerTests; + sourceTree = ""; + }; + 534453011E6217D600649AF9 /* Controllers */ = { + isa = PBXGroup; + children = ( + 5367B25D1E608BE4001744C8 /* MasterViewController.swift */, + 5367B2631E60A1A9001744C8 /* MapViewController.swift */, + 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + 534453021E6217E300649AF9 /* Delegates and DataSources */ = { + isa = PBXGroup; + children = ( + 5367B24B1E608B79001744C8 /* AppDelegate.swift */, + 5367B2611E60A140001744C8 /* LocationDataSource.swift */, + ); + name = "Delegates and DataSources"; + sourceTree = ""; + }; + 534453031E6217F800649AF9 /* Model */ = { + isa = PBXGroup; + children = ( + 534452FD1E61DF6100649AF9 /* locations.plist */, + 5367B2711E60A694001744C8 /* Location.swift */, + ); + name = Model; + sourceTree = ""; + }; + 534453041E62181D00649AF9 /* Views */ = { + isa = PBXGroup; + children = ( + 5367B2681E60A3C3001744C8 /* LocationCell.swift */, + 5367B24F1E608B79001744C8 /* Main.storyboard */, + 5367B2521E608B79001744C8 /* Assets.xcassets */, + 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */, + ); + name = Views; + sourceTree = ""; + }; + 534453051E62182900649AF9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5367B2571E608B79001744C8 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 5367B23F1E608B79001744C8 = { + isa = PBXGroup; + children = ( + 534452FF1E6216A100649AF9 /* README.md */, + 5367B24A1E608B79001744C8 /* Container */, + 534452F01E61B9E600649AF9 /* ContainerTests */, + 5367B2491E608B79001744C8 /* Products */, + 5367B2651E60A29E001744C8 /* Frameworks */, + ); + sourceTree = ""; + }; + 5367B2491E608B79001744C8 /* Products */ = { + isa = PBXGroup; + children = ( + 5367B2481E608B79001744C8 /* Container.app */, + 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5367B24A1E608B79001744C8 /* Container */ = { + isa = PBXGroup; + children = ( + 5367B26C1E60A5F0001744C8 /* Protocols and Extensions */, + 534453031E6217F800649AF9 /* Model */, + 534453011E6217D600649AF9 /* Controllers */, + 534453021E6217E300649AF9 /* Delegates and DataSources */, + 534453041E62181D00649AF9 /* Views */, + 534453051E62182900649AF9 /* Supporting Files */, + ); + path = Container; + sourceTree = ""; + }; + 5367B2651E60A29E001744C8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5367B2661E60A29E001744C8 /* MapKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5367B26C1E60A5F0001744C8 /* Protocols and Extensions */ = { + isa = PBXGroup; + children = ( + 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */, + 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */, + ); + name = "Protocols and Extensions"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 534452EE1E61B9E600649AF9 /* ContainerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 534452F61E61B9E600649AF9 /* Build configuration list for PBXNativeTarget "ContainerTests" */; + buildPhases = ( + 534452EB1E61B9E600649AF9 /* Sources */, + 534452EC1E61B9E600649AF9 /* Frameworks */, + 534452ED1E61B9E600649AF9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 534452F51E61B9E600649AF9 /* PBXTargetDependency */, + ); + name = ContainerTests; + productName = ContainerTests; + productReference = 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5367B2471E608B79001744C8 /* Container */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5367B25A1E608B79001744C8 /* Build configuration list for PBXNativeTarget "Container" */; + buildPhases = ( + 5367B2441E608B79001744C8 /* Sources */, + 5367B2451E608B79001744C8 /* Frameworks */, + 5367B2461E608B79001744C8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Container; + productName = Container; + productReference = 5367B2481E608B79001744C8 /* Container.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5367B2401E608B79001744C8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 534452EE1E61B9E600649AF9 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + TestTargetID = 5367B2471E608B79001744C8; + }; + 5367B2471E608B79001744C8 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 5367B2431E608B79001744C8 /* Build configuration list for PBXProject "Container" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5367B23F1E608B79001744C8; + productRefGroup = 5367B2491E608B79001744C8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5367B2471E608B79001744C8 /* Container */, + 534452EE1E61B9E600649AF9 /* ContainerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 534452ED1E61B9E600649AF9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2461E608B79001744C8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5367B2561E608B79001744C8 /* LaunchScreen.storyboard in Resources */, + 534452FE1E61DF6200649AF9 /* locations.plist in Resources */, + 5367B2531E608B79001744C8 /* Assets.xcassets in Resources */, + 5367B2511E608B79001744C8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 534452EB1E61B9E600649AF9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 534452FA1E61BA1F00649AF9 /* LocationTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2441E608B79001744C8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5367B26B1E60A5C6001744C8 /* ReusableIdentifier.swift in Sources */, + 5367B2691E60A3C3001744C8 /* LocationCell.swift in Sources */, + 5367B26E1E60A641001744C8 /* ConfigurableCell.swift in Sources */, + 5367B25E1E608BE4001744C8 /* MasterViewController.swift in Sources */, + 5367B2721E60A694001744C8 /* Location.swift in Sources */, + 5367B24C1E608B79001744C8 /* AppDelegate.swift in Sources */, + 5367B2601E60A129001744C8 /* LocationTableViewController.swift in Sources */, + 5367B2641E60A1A9001744C8 /* MapViewController.swift in Sources */, + 5367B2621E60A140001744C8 /* LocationDataSource.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 534452F51E61B9E600649AF9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5367B2471E608B79001744C8 /* Container */; + targetProxy = 534452F41E61B9E600649AF9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5367B24F1E608B79001744C8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5367B2501E608B79001744C8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5367B2551E608B79001744C8 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 534452F71E61B9E600649AF9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ContainerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ContainerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Container.app/Container"; + }; + name = Debug; + }; + 534452F81E61B9E600649AF9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ContainerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ContainerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Container.app/Container"; + }; + name = Release; + }; + 5367B2581E608B79001744C8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5367B2591E608B79001744C8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5367B25B1E608B79001744C8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Container/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Container; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5367B25C1E608B79001744C8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Container/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Container; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 534452F61E61B9E600649AF9 /* Build configuration list for PBXNativeTarget "ContainerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 534452F71E61B9E600649AF9 /* Debug */, + 534452F81E61B9E600649AF9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5367B2431E608B79001744C8 /* Build configuration list for PBXProject "Container" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5367B2581E608B79001744C8 /* Debug */, + 5367B2591E608B79001744C8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5367B25A1E608B79001744C8 /* Build configuration list for PBXNativeTarget "Container" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5367B25B1E608B79001744C8 /* Debug */, + 5367B25C1E608B79001744C8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5367B2401E608B79001744C8 /* Project object */; +} diff --git a/Container/Container-SB/Container/AppDelegate.swift b/Container/Container-SB/Container/AppDelegate.swift new file mode 100644 index 0000000..1e60a63 --- /dev/null +++ b/Container/Container-SB/Container/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/Container/Container-SB/Container/Assets.xcassets/AppIcon.appiconset/Contents.json b/Container/Container-SB/Container/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/Container/Container-SB/Container/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Container/Container-SB/Container/Base.lproj/LaunchScreen.storyboard b/Container/Container-SB/Container/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Container/Container-SB/Container/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Container/Container-SB/Container/Base.lproj/Main.storyboard b/Container/Container-SB/Container/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e5bdbfe --- /dev/null +++ b/Container/Container-SB/Container/Base.lproj/Main.storyboard @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Container/Container-SB/Container/ConfigurableCell.swift b/Container/Container-SB/Container/ConfigurableCell.swift new file mode 100644 index 0000000..eced6d5 --- /dev/null +++ b/Container/Container-SB/Container/ConfigurableCell.swift @@ -0,0 +1,38 @@ +// +// ConfigurableCell.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ConfigurableCell { + associatedtype Object + func configure(object: Object) +} diff --git a/Container/Container-SB/Container/Info.plist b/Container/Container-SB/Container/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Container/Container-SB/Container/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Container/Container-SB/Container/Location.swift b/Container/Container-SB/Container/Location.swift new file mode 100644 index 0000000..d65003c --- /dev/null +++ b/Container/Container-SB/Container/Location.swift @@ -0,0 +1,96 @@ +// +// Location.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import CoreLocation + +/// A structure representing the location of a point on +/// the map. + +struct Location { + + /// The name of the location. + + let name: String + + /// The latitude of the location in degrees. + + let latitude: CLLocationDegrees + + /// The longitude of the location in degrees. + + let longitude: CLLocationDegrees + + /// A read-only `CLLocationCoordinate2D` value for the + /// geographic coordinate of the location. + + var coordinate: CLLocationCoordinate2D { + return CLLocationCoordinate2DMake(latitude, longitude) + } +} + +extension Location { + + /// A failable initializer that builds a `Location` from + /// a dictionary of String keys and values. The dictionary + /// must contain at least "name", "latitude" and "longitude" + /// items. + /// + /// The values must all be `String` and the `latitude` + /// and `longitude` must convert to a `CLLocationDegrees` + /// value (Double) and specify a valid coordinate. A valid + /// latitude is from -90 to +90 and a valid longitude is + /// from -180 to +180. + /// + /// - Parameter dictionary: A dictionary containing the + /// details to initialize the location. + /// + /// - Returns: A `Location` structure or `nil` if the + /// dictionary was invalid, + + init?(dictionary: Dictionary) { + guard let name = dictionary["name"], + let latitudeItem = dictionary["latitude"], + let latitude = CLLocationDegrees(latitudeItem), + let longitudeItem = dictionary["longitude"], + let longitude = CLLocationDegrees(longitudeItem) else { + return nil + } + + self.name = name + self.latitude = latitude + self.longitude = longitude + if !CLLocationCoordinate2DIsValid(coordinate) { + return nil + } + } +} diff --git a/Container/Container-SB/Container/LocationCell.swift b/Container/Container-SB/Container/LocationCell.swift new file mode 100644 index 0000000..a2b4da9 --- /dev/null +++ b/Container/Container-SB/Container/LocationCell.swift @@ -0,0 +1,46 @@ +// +// LocationCell.swift +// Container +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017-2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LocationCell: UITableViewCell, ReusableIdentifier { + @IBOutlet private var name: UILabel! + @IBOutlet private var coordinates: UILabel! +} + +extension LocationCell: ConfigurableCell { + func configure(object: Location) { + name.text = object.name + coordinates.text = String("\(object.latitude) \(object.longitude)") + } +} diff --git a/Container/Container-SB/Container/LocationDataSource.swift b/Container/Container-SB/Container/LocationDataSource.swift new file mode 100644 index 0000000..96ac6e3 --- /dev/null +++ b/Container/Container-SB/Container/LocationDataSource.swift @@ -0,0 +1,88 @@ +// +// LocationDataSource.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LocationDataSource: NSObject { + + private let tableView: UITableView + private var locations = [Location]() + + init(tableView: UITableView, from path: String) { + self.tableView = tableView + super.init() + readFromPlist(name: path) + tableView.dataSource = self + tableView.reloadData() + } + + func locationAtIndexPath(_ indexPath: IndexPath) -> Location? { + return indexPath.row < locations.count ? locations[indexPath.row] : nil + } + + private func readFromPlist(name: String) { + guard let items = NSArray(contentsOfFile: name) as? [Dictionary] else { + return + } + for item in items { + if let location = Location(dictionary: item) { + locations.append(location) + } + } + } +} + +extension LocationDataSource: UITableViewDataSource { + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return locations.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: LocationCell.reuseIdentifier, for: indexPath) + configure(cell: cell, indexPath: indexPath) + return cell + } + + private func configure(cell: UITableViewCell, indexPath: IndexPath) { + if let cell = cell as? LocationCell { + let object = locations[indexPath.row] + cell.configure(object: object) + } + } +} + diff --git a/Container/Container-SB/Container/LocationTableViewController.swift b/Container/Container-SB/Container/LocationTableViewController.swift new file mode 100644 index 0000000..fa87ebb --- /dev/null +++ b/Container/Container-SB/Container/LocationTableViewController.swift @@ -0,0 +1,63 @@ +// +// LocationTableViewController.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol LocationProviderDelegate: AnyObject { + func didSelectLocation(_ location: Location) +} + +final class LocationTableViewController: UITableViewController { + + weak var delegate:LocationProviderDelegate? + + private var locationDataSource: LocationDataSource? + + override func viewDidLoad() { + super.viewDidLoad() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = UITableView.automaticDimension + tableView.delegate = self + + if let plistPath = Bundle.main.path(forResource: "locations", ofType: "plist") { + locationDataSource = LocationDataSource(tableView: tableView, from: plistPath) + tableView.dataSource = locationDataSource + } + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if let location = locationDataSource?.locationAtIndexPath(indexPath) { + delegate?.didSelectLocation(location) + } + } +} diff --git a/Container/Container-SB/Container/MapViewController.swift b/Container/Container-SB/Container/MapViewController.swift new file mode 100644 index 0000000..34ab9c7 --- /dev/null +++ b/Container/Container-SB/Container/MapViewController.swift @@ -0,0 +1,92 @@ +// +// MapViewController.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit +import MapKit + +final class MapViewController: UIViewController { + + @IBOutlet private var mapView: MKMapView! + + /// The zoom level to use when setting the span + /// of the map region to show. Default is 10 degrees. + + var zoom: CLLocationDegrees = 10.0 + + /// The coordinate to center the map on. Setting a new + /// coordinate centers the map on a region spanned by + /// the `zoom` level and drops a pin annotation at the + /// coordinate. + + var coordinate: CLLocationCoordinate2D? { + didSet { + if let coordinate = coordinate { + centerMap(coordinate) + annotate(coordinate) + } + } + } + + private func centerMap(_ coordinate: CLLocationCoordinate2D) { + let span = MKCoordinateSpan.init(latitudeDelta: zoom, longitudeDelta: zoom) + let region = MKCoordinateRegion(center: coordinate, span: span) + mapView.setRegion(region, animated: true) + } + + private func annotate(_ coordinate: CLLocationCoordinate2D) { + let annotation = MKPointAnnotation() + annotation.coordinate = coordinate + mapView.addAnnotation(annotation) + } +} + +extension MapViewController: MKMapViewDelegate { + + private enum AnnotationView: String { + case pin = "Pin" + } + + func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { + guard let annotation = annotation as? MKPointAnnotation else { + return nil + } + + let identifier = AnnotationView.pin.rawValue + guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView else { + return MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) + } + + annotationView.annotation = annotation + return annotationView + } +} diff --git a/Container/Container-SB/Container/MasterViewController.swift b/Container/Container-SB/Container/MasterViewController.swift new file mode 100644 index 0000000..13c91d1 --- /dev/null +++ b/Container/Container-SB/Container/MasterViewController.swift @@ -0,0 +1,86 @@ +// +// MasterViewController.swift +// Container +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017-2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class MasterViewController: UIViewController { + @IBOutlet private var topStackView: UIStackView! + private var locationTableViewController: LocationTableViewController? + private var mapViewController: MapViewController? + +// override func viewDidLoad() { +// super.viewDidLoad() +// guard let locationController = childViewControllers.first as? LocationTableViewController else { +// fatalError("Check storyboard for missing LocationTableViewController") +// } +// +// guard let mapController = childViewControllers.last as? MapViewController else { +// fatalError("Check storyboard for missing MapViewController") +// } +// +// locationTableViewController = locationController +// mapViewController = mapController +// locationController.delegate = self +// } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + topStackView.axis = axisForSize(view.bounds.size) + } + + // Alternative to wiring up the interface in viewDidLoad (above) is to + // use prepare(for segue:sender:) which is still called for + // embed segues. + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + let destination = segue.destination + if let locationController = destination as? LocationTableViewController { + locationTableViewController = locationController + locationController.delegate = self + } + + if let mapController = destination as? MapViewController { + mapViewController = mapController + } + } + + private func axisForSize(_ size: CGSize) -> NSLayoutConstraint.Axis { + return size.width > size.height ? .horizontal : .vertical + } +} + +extension MasterViewController: LocationProviderDelegate { + func didSelectLocation(_ location: Location) { + mapViewController?.coordinate = location.coordinate + } +} diff --git a/Container/Container-SB/Container/ReusableIdentifier.swift b/Container/Container-SB/Container/ReusableIdentifier.swift new file mode 100644 index 0000000..893e7f4 --- /dev/null +++ b/Container/Container-SB/Container/ReusableIdentifier.swift @@ -0,0 +1,43 @@ +// +// ReusableIdentifier.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ReusableIdentifier: class { + static var reuseIdentifier: String { get } +} + +extension ReusableIdentifier { + static var reuseIdentifier: String { + return "\(self)" + } +} diff --git a/Container/Container-SB/Container/locations.plist b/Container/Container-SB/Container/locations.plist new file mode 100644 index 0000000..1d4ad3c --- /dev/null +++ b/Container/Container-SB/Container/locations.plist @@ -0,0 +1,247 @@ +( +{name="Afghanistan";latitude="33.93911";longitude="67.709953";}, +{name="Albania";latitude="41.153332";longitude="20.168331";}, +{name="Algeria";latitude="28.033886";longitude="1.659626";}, +{name="American Samoa";latitude="-14.270972";longitude="-170.132217";}, +{name="Andorra";latitude="42.546245";longitude="1.601554";}, +{name="Angola";latitude="-11.202692";longitude="17.873887";}, +{name="Anguilla";latitude="18.220554";longitude="-63.068615";}, +{name="Antarctica";latitude="-75.250973";longitude="-0.071389";}, +{name="Antigua and Barbuda";latitude="17.060816";longitude="-61.796428";}, +{name="Argentina";latitude="-38.416097";longitude="-63.616672";}, +{name="Armenia";latitude="40.069099";longitude="45.038189";}, +{name="Aruba";latitude="12.52111";longitude="-69.968338";}, +{name="Australia";latitude="-25.274398";longitude="133.775136";}, +{name="Austria";latitude="47.516231";longitude="14.550072";}, +{name="Azerbaijan";latitude="40.143105";longitude="47.576927";}, +{name="Bahamas";latitude="25.03428";longitude="-77.39628";}, +{name="Bahrain";latitude="25.930414";longitude="50.637772";}, +{name="Bangladesh";latitude="23.684994";longitude="90.356331";}, +{name="Barbados";latitude="13.193887";longitude="-59.543198";}, +{name="Belarus";latitude="53.709807";longitude="27.953389";}, +{name="Belgium";latitude="50.503887";longitude="4.469936";}, +{name="Belize";latitude="17.189877";longitude="-88.49765";}, +{name="Benin";latitude="9.30769";longitude="2.315834";}, +{name="Bermuda";latitude="32.321384";longitude="-64.75737";}, +{name="Bhutan";latitude="27.514162";longitude="90.433601";}, +{name="Bolivia";latitude="-16.290154";longitude="-63.588653";}, +{name="Bosnia and Herzegovina";latitude="43.915886";longitude="17.679076";}, +{name="Botswana";latitude="-22.328474";longitude="24.684866";}, +{name="Bouvet Island";latitude="-54.423199";longitude="3.413194";}, +{name="Brazil";latitude="-14.235004";longitude="-51.92528";}, +{name="British Indian Ocean Territory";latitude="-6.343194";longitude="71.876519";}, +{name="British Virgin Islands";latitude="18.420695";longitude="-64.639968";}, +{name="Brunei";latitude="4.535277";longitude="114.727669";}, +{name="Bulgaria";latitude="42.733883";longitude="25.48583";}, +{name="Burkina Faso";latitude="12.238333";longitude="-1.561593";}, +{name="Burundi";latitude="-3.373056";longitude="29.918886";}, +{name="Cambodia";latitude="12.565679";longitude="104.990963";}, +{name="Cameroon";latitude="7.369722";longitude="12.354722";}, +{name="Canada";latitude="56.130366";longitude="-106.346771";}, +{name="Cape Verde";latitude="16.002082";longitude="-24.013197";}, +{name="Cayman Islands";latitude="19.513469";longitude="-80.566956";}, +{name="Central African Republic";latitude="6.611111";longitude="20.939444";}, +{name="Chad";latitude="15.454166";longitude="18.732207";}, +{name="Chile";latitude="-35.675147";longitude="-71.542969";}, +{name="China";latitude="35.86166";longitude="104.195397";}, +{name="Christmas Island";latitude="-10.447525";longitude="105.690449";}, +{name="Cocos [Keeling] Islands";latitude="-12.164165";longitude="96.870956";}, +{name="Colombia";latitude="4.570868";longitude="-74.297333";}, +{name="Comoros";latitude="-11.875001";longitude="43.872219";}, +{name="Congo [DRC]";latitude="-4.038333";longitude="21.758664";}, +{name="Congo [Republic]";latitude="-0.228021";longitude="15.827659";}, +{name="Cook Islands";latitude="-21.236736";longitude="-159.777671";}, +{name="Costa Rica";latitude="9.748917";longitude="-83.753428";}, +{name="Croatia";latitude="45.1";longitude="15.2";}, +{name="Cuba";latitude="21.521757";longitude="-77.781167";}, +{name="Cyprus";latitude="35.126413";longitude="33.429859";}, +{name="Czech Republic";latitude="49.817492";longitude="15.472962";}, +{name="Côte d'Ivoire";latitude="7.539989";longitude="-5.54708";}, +{name="Denmark";latitude="56.26392";longitude="9.501785";}, +{name="Djibouti";latitude="11.825138";longitude="42.590275";}, +{name="Dominica";latitude="15.414999";longitude="-61.370976";}, +{name="Dominican Republic";latitude="18.735693";longitude="-70.162651";}, +{name="Ecuador";latitude="-1.831239";longitude="-78.183406";}, +{name="Egypt";latitude="26.820553";longitude="30.802498";}, +{name="El Salvador";latitude="13.794185";longitude="-88.89653";}, +{name="Equatorial Guinea";latitude="1.650801";longitude="10.267895";}, +{name="Eritrea";latitude="15.179384";longitude="39.782334";}, +{name="Estonia";latitude="58.595272";longitude="25.013607";}, +{name="Ethiopia";latitude="9.145";longitude="40.489673";}, +{name="Falkland Islands [Islas Malvinas]";latitude="-51.796253";longitude="-59.523613";}, +{name="Faroe Islands";latitude="61.892635";longitude="-6.911806";}, +{name="Fiji";latitude="-16.578193";longitude="179.414413";}, +{name="Finland";latitude="61.92411";longitude="25.748151";}, +{name="France";latitude="46.227638";longitude="2.213749";}, +{name="French Guiana";latitude="3.933889";longitude="-53.125782";}, +{name="French Polynesia";latitude="-17.679742";longitude="-149.406843";}, +{name="French Southern Territories";latitude="-49.280366";longitude="69.348557";}, +{name="Gabon";latitude="-0.803689";longitude="11.609444";}, +{name="Gambia";latitude="13.443182";longitude="-15.310139";}, +{name="Gaza Strip";latitude="31.354676";longitude="34.308825";}, +{name="Georgia";latitude="42.315407";longitude="43.356892";}, +{name="Germany";latitude="51.165691";longitude="10.451526";}, +{name="Ghana";latitude="7.946527";longitude="-1.023194";}, +{name="Gibraltar";latitude="36.137741";longitude="-5.345374";}, +{name="Greece";latitude="39.074208";longitude="21.824312";}, +{name="Greenland";latitude="71.706936";longitude="-42.604303";}, +{name="Grenada";latitude="12.262776";longitude="-61.604171";}, +{name="Guadeloupe";latitude="16.995971";longitude="-62.067641";}, +{name="Guam";latitude="13.444304";longitude="144.793731";}, +{name="Guatemala";latitude="15.783471";longitude="-90.230759";}, +{name="Guernsey";latitude="49.465691";longitude="-2.585278";}, +{name="Guinea";latitude="9.945587";longitude="-9.696645";}, +{name="Guinea-Bissau";latitude="11.803749";longitude="-15.180413";}, +{name="Guyana";latitude="4.860416";longitude="-58.93018";}, +{name="Haiti";latitude="18.971187";longitude="-72.285215";}, +{name="Heard Island and McDonald Islands";latitude="-53.08181";longitude="73.504158";}, +{name="Honduras";latitude="15.199999";longitude="-86.241905";}, +{name="Hong Kong";latitude="22.396428";longitude="114.109497";}, +{name="Hungary";latitude="47.162494";longitude="19.503304";}, +{name="Iceland";latitude="64.963051";longitude="-19.020835";}, +{name="India";latitude="20.593684";longitude="78.96288";}, +{name="Indonesia";latitude="-0.789275";longitude="113.921327";}, +{name="Iran";latitude="32.427908";longitude="53.688046";}, +{name="Iraq";latitude="33.223191";longitude="43.679291";}, +{name="Ireland";latitude="53.41291";longitude="-8.24389";}, +{name="Isle of Man";latitude="54.236107";longitude="-4.548056";}, +{name="Israel";latitude="31.046051";longitude="34.851612";}, +{name="Italy";latitude="41.87194";longitude="12.56738";}, +{name="Jamaica";latitude="18.109581";longitude="-77.297508";}, +{name="Japan";latitude="36.204824";longitude="138.252924";}, +{name="Jersey";latitude="49.214439";longitude="-2.13125";}, +{name="Jordan";latitude="30.585164";longitude="36.238414";}, +{name="Kazakhstan";latitude="48.019573";longitude="66.923684";}, +{name="Kenya";latitude="-0.023559";longitude="37.906193";}, +{name="Kiribati";latitude="-3.370417";longitude="-168.734039";}, +{name="Kosovo";latitude="42.602636";longitude="20.902977";}, +{name="Kuwait";latitude="29.31166";longitude="47.481766";}, +{name="Kyrgyzstan";latitude="41.20438";longitude="74.766098";}, +{name="Laos";latitude="19.85627";longitude="102.495496";}, +{name="Latvia";latitude="56.879635";longitude="24.603189";}, +{name="Lebanon";latitude="33.854721";longitude="35.862285";}, +{name="Lesotho";latitude="-29.609988";longitude="28.233608";}, +{name="Liberia";latitude="6.428055";longitude="-9.429499";}, +{name="Libya";latitude="26.3351";longitude="17.228331";}, +{name="Liechtenstein";latitude="47.166";longitude="9.555373";}, +{name="Lithuania";latitude="55.169438";longitude="23.881275";}, +{name="Luxembourg";latitude="49.815273";longitude="6.129583";}, +{name="Macau";latitude="22.198745";longitude="113.543873";}, +{name="Macedonia [FYROM]";latitude="41.608635";longitude="21.745275";}, +{name="Madagascar";latitude="-18.766947";longitude="46.869107";}, +{name="Malawi";latitude="-13.254308";longitude="34.301525";}, +{name="Malaysia";latitude="4.210484";longitude="101.975766";}, +{name="Maldives";latitude="3.202778";longitude="73.22068";}, +{name="Mali";latitude="17.570692";longitude="-3.996166";}, +{name="Malta";latitude="35.937496";longitude="14.375416";}, +{name="Marshall Islands";latitude="7.131474";longitude="171.184478";}, +{name="Martinique";latitude="14.641528";longitude="-61.024174";}, +{name="Mauritania";latitude="21.00789";longitude="-10.940835";}, +{name="Mauritius";latitude="-20.348404";longitude="57.552152";}, +{name="Mayotte";latitude="-12.8275";longitude="45.166244";}, +{name="Mexico";latitude="23.634501";longitude="-102.552784";}, +{name="Micronesia";latitude="7.425554";longitude="150.550812";}, +{name="Moldova";latitude="47.411631";longitude="28.369885";}, +{name="Monaco";latitude="43.750298";longitude="7.412841";}, +{name="Mongolia";latitude="46.862496";longitude="103.846656";}, +{name="Montenegro";latitude="42.708678";longitude="19.37439";}, +{name="Montserrat";latitude="16.742498";longitude="-62.187366";}, +{name="Morocco";latitude="31.791702";longitude="-7.09262";}, +{name="Mozambique";latitude="-18.665695";longitude="35.529562";}, +{name="Myanmar [Burma]";latitude="21.913965";longitude="95.956223";}, +{name="Namibia";latitude="-22.95764";longitude="18.49041";}, +{name="Nauru";latitude="-0.522778";longitude="166.931503";}, +{name="Nepal";latitude="28.394857";longitude="84.124008";}, +{name="Netherlands Antilles";latitude="12.226079";longitude="-69.060087";}, +{name="Netherlands";latitude="52.132633";longitude="5.291266";}, +{name="New Caledonia";latitude="-20.904305";longitude="165.618042";}, +{name="New Zealand";latitude="-40.900557";longitude="174.885971";}, +{name="Nicaragua";latitude="12.865416";longitude="-85.207229";}, +{name="Niger";latitude="17.607789";longitude="8.081666";}, +{name="Nigeria";latitude="9.081999";longitude="8.675277";}, +{name="Niue";latitude="-19.054445";longitude="-169.867233";}, +{name="Norfolk Island";latitude="-29.040835";longitude="167.954712";}, +{name="North Korea";latitude="40.339852";longitude="127.510093";}, +{name="Northern Mariana Islands";latitude="17.33083";longitude="145.38469";}, +{name="Norway";latitude="60.472024";longitude="8.468946";}, +{name="Oman";latitude="21.512583";longitude="55.923255";}, +{name="Pakistan";latitude="30.375321";longitude="69.345116";}, +{name="Palau";latitude="7.51498";longitude="134.58252";}, +{name="Palestinian Territories";latitude="31.952162";longitude="35.233154";}, +{name="Panama";latitude="8.537981";longitude="-80.782127";}, +{name="Papua New Guinea";latitude="-6.314993";longitude="143.95555";}, +{name="Paraguay";latitude="-23.442503";longitude="-58.443832";}, +{name="Peru";latitude="-9.189967";longitude="-75.015152";}, +{name="Philippines";latitude="12.879721";longitude="121.774017";}, +{name="Pitcairn Islands";latitude="-24.703615";longitude="-127.439308";}, +{name="Poland";latitude="51.919438";longitude="19.145136";}, +{name="Portugal";latitude="39.399872";longitude="-8.224454";}, +{name="Puerto Rico";latitude="18.220833";longitude="-66.590149";}, +{name="Qatar";latitude="25.354826";longitude="51.183884";}, +{name="Romania";latitude="45.943161";longitude="24.96676";}, +{name="Russia";latitude="61.52401";longitude="105.318756";}, +{name="Rwanda";latitude="-1.940278";longitude="29.873888";}, +{name="Réunion";latitude="-21.115141";longitude="55.536384";}, +{name="Saint Helena";latitude="-24.143474";longitude="-10.030696";}, +{name="Saint Kitts and Nevis";latitude="17.357822";longitude="-62.782998";}, +{name="Saint Lucia";latitude="13.909444";longitude="-60.978893";}, +{name="Saint Pierre and Miquelon";latitude="46.941936";longitude="-56.27111";}, +{name="Saint Vincent and the Grenadines";latitude="12.984305";longitude="-61.287228";}, +{name="Samoa";latitude="-13.759029";longitude="-172.104629";}, +{name="San Marino";latitude="43.94236";longitude="12.457777";}, +{name="Saudi Arabia";latitude="23.885942";longitude="45.079162";}, +{name="Senegal";latitude="14.497401";longitude="-14.452362";}, +{name="Serbia";latitude="44.016521";longitude="21.005859";}, +{name="Seychelles";latitude="-4.679574";longitude="55.491977";}, +{name="Sierra Leone";latitude="8.460555";longitude="-11.779889";}, +{name="Singapore";latitude="1.352083";longitude="103.819836";}, +{name="Slovakia";latitude="48.669026";longitude="19.699024";}, +{name="Slovenia";latitude="46.151241";longitude="14.995463";}, +{name="Solomon Islands";latitude="-9.64571";longitude="160.156194";}, +{name="Somalia";latitude="5.152149";longitude="46.199616";}, +{name="South Africa";latitude="-30.559482";longitude="22.937506";}, +{name="South Georgia and the South Sandwich Islands";latitude="-54.429579";longitude="-36.587909";}, +{name="South Korea";latitude="35.907757";longitude="127.766922";}, +{name="Spain";latitude="40.463667";longitude="-3.74922";}, +{name="Sri Lanka";latitude="7.873054";longitude="80.771797";}, +{name="Sudan";latitude="12.862807";longitude="30.217636";}, +{name="Suriname";latitude="3.919305";longitude="-56.027783";}, +{name="Svalbard and Jan Mayen";latitude="77.553604";longitude="23.670272";}, +{name="Swaziland";latitude="-26.522503";longitude="31.465866";}, +{name="Sweden";latitude="60.128161";longitude="18.643501";}, +{name="Switzerland";latitude="46.818188";longitude="8.227512";}, +{name="Syria";latitude="34.802075";longitude="38.996815";}, +{name="São Tomé and Príncipe";latitude="0.18636";longitude="6.613081";}, +{name="Taiwan";latitude="23.69781";longitude="120.960515";}, +{name="Tajikistan";latitude="38.861034";longitude="71.276093";}, +{name="Tanzania";latitude="-6.369028";longitude="34.888822";}, +{name="Thailand";latitude="15.870032";longitude="100.992541";}, +{name="Timor-Leste";latitude="-8.874217";longitude="125.727539";}, +{name="Togo";latitude="8.619543";longitude="0.824782";}, +{name="Tokelau";latitude="-8.967363";longitude="-171.855881";}, +{name="Tonga";latitude="-21.178986";longitude="-175.198242";}, +{name="Trinidad and Tobago";latitude="10.691803";longitude="-61.222503";}, +{name="Tunisia";latitude="33.886917";longitude="9.537499";}, +{name="Turkey";latitude="38.963745";longitude="35.243322";}, +{name="Turkmenistan";latitude="38.969719";longitude="59.556278";}, +{name="Turks and Caicos Islands";latitude="21.694025";longitude="-71.797928";}, +{name="Tuvalu";latitude="-7.109535";longitude="177.64933";}, +{name="U.S. Minor Outlying Islands";latitude="";longitude="";}, +{name="U.S. Virgin Islands";latitude="18.335765";longitude="-64.896335";}, +{name="Uganda";latitude="1.373333";longitude="32.290275";}, +{name="Ukraine";latitude="48.379433";longitude="31.16558";}, +{name="United Arab Emirates";latitude="23.424076";longitude="53.847818";}, +{name="United Kingdom";latitude="55.378051";longitude="-3.435973";}, +{name="United States";latitude="37.09024";longitude="-95.712891";}, +{name="Uruguay";latitude="-32.522779";longitude="-55.765835";}, +{name="Uzbekistan";latitude="41.377491";longitude="64.585262";}, +{name="Vanuatu";latitude="-15.376706";longitude="166.959158";}, +{name="Vatican City";latitude="41.902916";longitude="12.453389";}, +{name="Venezuela";latitude="6.42375";longitude="-66.58973";}, +{name="Vietnam";latitude="14.058324";longitude="108.277199";}, +{name="Wallis and Futuna";latitude="-13.768752";longitude="-177.156097";}, +{name="Western Sahara";latitude="24.215527";longitude="-12.885834";}, +{name="Yemen";latitude="15.552727";longitude="48.516388";}, +{name="Zambia";latitude="-13.133897";longitude="27.849332";}, +{name="Zimbabwe";latitude="-19.015438";longitude="29.154857";} +) diff --git a/Container/Container-SB/ContainerTests/Info.plist b/Container/Container-SB/ContainerTests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Container/Container-SB/ContainerTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Container/Container-SB/ContainerTests/LocationTests.swift b/Container/Container-SB/ContainerTests/LocationTests.swift new file mode 100644 index 0000000..93179fa --- /dev/null +++ b/Container/Container-SB/ContainerTests/LocationTests.swift @@ -0,0 +1,105 @@ +// +// LocationTests.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import XCTest +import CoreLocation + +@testable import Container + +class LocationTests: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInitFromDictionary() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "135"]) + XCTAssertNotNil(australia) + XCTAssert(australia?.name == "Australia") + XCTAssert(australia?.latitude == -25.0) + XCTAssert(australia?.longitude == 135.0) + } + + func testMissingName() { + let australia = Location(dictionary: ["latitude" : "-25", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testMissingLatitude() { + let australia = Location(dictionary: ["name" : "Australis", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testMissingLongitude() { + let australia = Location(dictionary: ["name" : "Australis", + "latitude" : "-25"]) + XCTAssertNil(australia) + } + + func testExtraKeysIgnored() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "135", + "capital" : "Canberra"]) + XCTAssertNotNil(australia) + } + + func testInvalidLatitude() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "hello", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testInvalidLongitude() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "12a"]) + XCTAssertNil(australia) + } + + func testInvalidCoordinare() { + let nowhere = Location(dictionary: ["name" : "OffTheGrid", + "latitude" : "-100", + "longitude" : "200"]) + XCTAssertNil(nowhere) + } +} diff --git a/Container/Container-SB/README.md b/Container/Container-SB/README.md new file mode 100644 index 0000000..ce4638f --- /dev/null +++ b/Container/Container-SB/README.md @@ -0,0 +1,6 @@ +### Attribution + +The country location data used in this example is based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). + +See the [original source page](https://developers.google.com/public-data/docs/canonical/countries_csv) for details. + diff --git a/Container/Container-code/Container.xcodeproj/project.pbxproj b/Container/Container-code/Container.xcodeproj/project.pbxproj new file mode 100644 index 0000000..53c988d --- /dev/null +++ b/Container/Container-code/Container.xcodeproj/project.pbxproj @@ -0,0 +1,539 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 534452FA1E61BA1F00649AF9 /* LocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534452F91E61BA1F00649AF9 /* LocationTests.swift */; }; + 534452FE1E61DF6200649AF9 /* locations.plist in Resources */ = {isa = PBXBuildFile; fileRef = 534452FD1E61DF6100649AF9 /* locations.plist */; }; + 5367B24C1E608B79001744C8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B24B1E608B79001744C8 /* AppDelegate.swift */; }; + 5367B2511E608B79001744C8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5367B24F1E608B79001744C8 /* Main.storyboard */; }; + 5367B2531E608B79001744C8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5367B2521E608B79001744C8 /* Assets.xcassets */; }; + 5367B2561E608B79001744C8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */; }; + 5367B25E1E608BE4001744C8 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B25D1E608BE4001744C8 /* MasterViewController.swift */; }; + 5367B2601E60A129001744C8 /* LocationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */; }; + 5367B2621E60A140001744C8 /* LocationDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2611E60A140001744C8 /* LocationDataSource.swift */; }; + 5367B2641E60A1A9001744C8 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2631E60A1A9001744C8 /* MapViewController.swift */; }; + 5367B2691E60A3C3001744C8 /* LocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2681E60A3C3001744C8 /* LocationCell.swift */; }; + 5367B26B1E60A5C6001744C8 /* ReusableIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */; }; + 5367B26E1E60A641001744C8 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */; }; + 5367B2721E60A694001744C8 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5367B2711E60A694001744C8 /* Location.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 534452F41E61B9E600649AF9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5367B2401E608B79001744C8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5367B2471E608B79001744C8; + remoteInfo = Container; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ContainerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 534452F31E61B9E600649AF9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 534452F91E61BA1F00649AF9 /* LocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTests.swift; sourceTree = ""; }; + 534452FD1E61DF6100649AF9 /* locations.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = locations.plist; sourceTree = ""; }; + 534452FF1E6216A100649AF9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; + 5367B2481E608B79001744C8 /* Container.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Container.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5367B24B1E608B79001744C8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5367B2501E608B79001744C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5367B2521E608B79001744C8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5367B2551E608B79001744C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5367B2571E608B79001744C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5367B25D1E608BE4001744C8 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationTableViewController.swift; sourceTree = ""; }; + 5367B2611E60A140001744C8 /* LocationDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationDataSource.swift; sourceTree = ""; }; + 5367B2631E60A1A9001744C8 /* MapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + 5367B2661E60A29E001744C8 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + 5367B2681E60A3C3001744C8 /* LocationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationCell.swift; sourceTree = ""; }; + 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableIdentifier.swift; sourceTree = ""; }; + 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; + 5367B2711E60A694001744C8 /* Location.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 534452EC1E61B9E600649AF9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2451E608B79001744C8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 534452F01E61B9E600649AF9 /* ContainerTests */ = { + isa = PBXGroup; + children = ( + 534452F91E61BA1F00649AF9 /* LocationTests.swift */, + 534452F31E61B9E600649AF9 /* Info.plist */, + ); + path = ContainerTests; + sourceTree = ""; + }; + 534453011E6217D600649AF9 /* Controllers */ = { + isa = PBXGroup; + children = ( + 5367B25D1E608BE4001744C8 /* MasterViewController.swift */, + 5367B2631E60A1A9001744C8 /* MapViewController.swift */, + 5367B25F1E60A129001744C8 /* LocationTableViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + 534453021E6217E300649AF9 /* Delegates and DataSources */ = { + isa = PBXGroup; + children = ( + 5367B24B1E608B79001744C8 /* AppDelegate.swift */, + 5367B2611E60A140001744C8 /* LocationDataSource.swift */, + ); + name = "Delegates and DataSources"; + sourceTree = ""; + }; + 534453031E6217F800649AF9 /* Model */ = { + isa = PBXGroup; + children = ( + 534452FD1E61DF6100649AF9 /* locations.plist */, + 5367B2711E60A694001744C8 /* Location.swift */, + ); + name = Model; + sourceTree = ""; + }; + 534453041E62181D00649AF9 /* Views */ = { + isa = PBXGroup; + children = ( + 5367B2681E60A3C3001744C8 /* LocationCell.swift */, + 5367B24F1E608B79001744C8 /* Main.storyboard */, + 5367B2521E608B79001744C8 /* Assets.xcassets */, + 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */, + ); + name = Views; + sourceTree = ""; + }; + 534453051E62182900649AF9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5367B2571E608B79001744C8 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 5367B23F1E608B79001744C8 = { + isa = PBXGroup; + children = ( + 534452FF1E6216A100649AF9 /* README.md */, + 5367B24A1E608B79001744C8 /* Container */, + 534452F01E61B9E600649AF9 /* ContainerTests */, + 5367B2491E608B79001744C8 /* Products */, + 5367B2651E60A29E001744C8 /* Frameworks */, + ); + sourceTree = ""; + }; + 5367B2491E608B79001744C8 /* Products */ = { + isa = PBXGroup; + children = ( + 5367B2481E608B79001744C8 /* Container.app */, + 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5367B24A1E608B79001744C8 /* Container */ = { + isa = PBXGroup; + children = ( + 5367B26C1E60A5F0001744C8 /* Protocols and Extensions */, + 534453031E6217F800649AF9 /* Model */, + 534453011E6217D600649AF9 /* Controllers */, + 534453021E6217E300649AF9 /* Delegates and DataSources */, + 534453041E62181D00649AF9 /* Views */, + 534453051E62182900649AF9 /* Supporting Files */, + ); + path = Container; + sourceTree = ""; + }; + 5367B2651E60A29E001744C8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5367B2661E60A29E001744C8 /* MapKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5367B26C1E60A5F0001744C8 /* Protocols and Extensions */ = { + isa = PBXGroup; + children = ( + 5367B26D1E60A641001744C8 /* ConfigurableCell.swift */, + 5367B26A1E60A5C6001744C8 /* ReusableIdentifier.swift */, + ); + name = "Protocols and Extensions"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 534452EE1E61B9E600649AF9 /* ContainerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 534452F61E61B9E600649AF9 /* Build configuration list for PBXNativeTarget "ContainerTests" */; + buildPhases = ( + 534452EB1E61B9E600649AF9 /* Sources */, + 534452EC1E61B9E600649AF9 /* Frameworks */, + 534452ED1E61B9E600649AF9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 534452F51E61B9E600649AF9 /* PBXTargetDependency */, + ); + name = ContainerTests; + productName = ContainerTests; + productReference = 534452EF1E61B9E600649AF9 /* ContainerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5367B2471E608B79001744C8 /* Container */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5367B25A1E608B79001744C8 /* Build configuration list for PBXNativeTarget "Container" */; + buildPhases = ( + 5367B2441E608B79001744C8 /* Sources */, + 5367B2451E608B79001744C8 /* Frameworks */, + 5367B2461E608B79001744C8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Container; + productName = Container; + productReference = 5367B2481E608B79001744C8 /* Container.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5367B2401E608B79001744C8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 534452EE1E61B9E600649AF9 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + TestTargetID = 5367B2471E608B79001744C8; + }; + 5367B2471E608B79001744C8 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 5367B2431E608B79001744C8 /* Build configuration list for PBXProject "Container" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5367B23F1E608B79001744C8; + productRefGroup = 5367B2491E608B79001744C8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5367B2471E608B79001744C8 /* Container */, + 534452EE1E61B9E600649AF9 /* ContainerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 534452ED1E61B9E600649AF9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2461E608B79001744C8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5367B2561E608B79001744C8 /* LaunchScreen.storyboard in Resources */, + 534452FE1E61DF6200649AF9 /* locations.plist in Resources */, + 5367B2531E608B79001744C8 /* Assets.xcassets in Resources */, + 5367B2511E608B79001744C8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 534452EB1E61B9E600649AF9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 534452FA1E61BA1F00649AF9 /* LocationTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5367B2441E608B79001744C8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5367B26B1E60A5C6001744C8 /* ReusableIdentifier.swift in Sources */, + 5367B2691E60A3C3001744C8 /* LocationCell.swift in Sources */, + 5367B26E1E60A641001744C8 /* ConfigurableCell.swift in Sources */, + 5367B25E1E608BE4001744C8 /* MasterViewController.swift in Sources */, + 5367B2721E60A694001744C8 /* Location.swift in Sources */, + 5367B24C1E608B79001744C8 /* AppDelegate.swift in Sources */, + 5367B2601E60A129001744C8 /* LocationTableViewController.swift in Sources */, + 5367B2641E60A1A9001744C8 /* MapViewController.swift in Sources */, + 5367B2621E60A140001744C8 /* LocationDataSource.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 534452F51E61B9E600649AF9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5367B2471E608B79001744C8 /* Container */; + targetProxy = 534452F41E61B9E600649AF9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5367B24F1E608B79001744C8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5367B2501E608B79001744C8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5367B2541E608B79001744C8 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5367B2551E608B79001744C8 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 534452F71E61B9E600649AF9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ContainerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ContainerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Container.app/Container"; + }; + name = Debug; + }; + 534452F81E61B9E600649AF9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ContainerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ContainerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Container.app/Container"; + }; + name = Release; + }; + 5367B2581E608B79001744C8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5367B2591E608B79001744C8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5367B25B1E608B79001744C8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Container/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Container; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5367B25C1E608B79001744C8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Container/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Container; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 534452F61E61B9E600649AF9 /* Build configuration list for PBXNativeTarget "ContainerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 534452F71E61B9E600649AF9 /* Debug */, + 534452F81E61B9E600649AF9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5367B2431E608B79001744C8 /* Build configuration list for PBXProject "Container" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5367B2581E608B79001744C8 /* Debug */, + 5367B2591E608B79001744C8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5367B25A1E608B79001744C8 /* Build configuration list for PBXNativeTarget "Container" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5367B25B1E608B79001744C8 /* Debug */, + 5367B25C1E608B79001744C8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5367B2401E608B79001744C8 /* Project object */; +} diff --git a/Container/Container-code/Container/AppDelegate.swift b/Container/Container-code/Container/AppDelegate.swift new file mode 100644 index 0000000..1e60a63 --- /dev/null +++ b/Container/Container-code/Container/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/Container/Container-code/Container/Assets.xcassets/AppIcon.appiconset/Contents.json b/Container/Container-code/Container/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/Container/Container-code/Container/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Container/Container-code/Container/Base.lproj/LaunchScreen.storyboard b/Container/Container-code/Container/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Container/Container-code/Container/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Container/Container-code/Container/Base.lproj/Main.storyboard b/Container/Container-code/Container/Base.lproj/Main.storyboard new file mode 100644 index 0000000..7a01916 --- /dev/null +++ b/Container/Container-code/Container/Base.lproj/Main.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Container/Container-code/Container/ConfigurableCell.swift b/Container/Container-code/Container/ConfigurableCell.swift new file mode 100644 index 0000000..eced6d5 --- /dev/null +++ b/Container/Container-code/Container/ConfigurableCell.swift @@ -0,0 +1,38 @@ +// +// ConfigurableCell.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ConfigurableCell { + associatedtype Object + func configure(object: Object) +} diff --git a/Container/Container-code/Container/Info.plist b/Container/Container-code/Container/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Container/Container-code/Container/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Container/Container-code/Container/Location.swift b/Container/Container-code/Container/Location.swift new file mode 100644 index 0000000..d65003c --- /dev/null +++ b/Container/Container-code/Container/Location.swift @@ -0,0 +1,96 @@ +// +// Location.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import CoreLocation + +/// A structure representing the location of a point on +/// the map. + +struct Location { + + /// The name of the location. + + let name: String + + /// The latitude of the location in degrees. + + let latitude: CLLocationDegrees + + /// The longitude of the location in degrees. + + let longitude: CLLocationDegrees + + /// A read-only `CLLocationCoordinate2D` value for the + /// geographic coordinate of the location. + + var coordinate: CLLocationCoordinate2D { + return CLLocationCoordinate2DMake(latitude, longitude) + } +} + +extension Location { + + /// A failable initializer that builds a `Location` from + /// a dictionary of String keys and values. The dictionary + /// must contain at least "name", "latitude" and "longitude" + /// items. + /// + /// The values must all be `String` and the `latitude` + /// and `longitude` must convert to a `CLLocationDegrees` + /// value (Double) and specify a valid coordinate. A valid + /// latitude is from -90 to +90 and a valid longitude is + /// from -180 to +180. + /// + /// - Parameter dictionary: A dictionary containing the + /// details to initialize the location. + /// + /// - Returns: A `Location` structure or `nil` if the + /// dictionary was invalid, + + init?(dictionary: Dictionary) { + guard let name = dictionary["name"], + let latitudeItem = dictionary["latitude"], + let latitude = CLLocationDegrees(latitudeItem), + let longitudeItem = dictionary["longitude"], + let longitude = CLLocationDegrees(longitudeItem) else { + return nil + } + + self.name = name + self.latitude = latitude + self.longitude = longitude + if !CLLocationCoordinate2DIsValid(coordinate) { + return nil + } + } +} diff --git a/Container/Container-code/Container/LocationCell.swift b/Container/Container-code/Container/LocationCell.swift new file mode 100644 index 0000000..ed28ed3 --- /dev/null +++ b/Container/Container-code/Container/LocationCell.swift @@ -0,0 +1,46 @@ +// +// LocationCell.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LocationCell: UITableViewCell, ReusableIdentifier { + @IBOutlet private var name: UILabel! + @IBOutlet private var coordinates: UILabel! +} + +extension LocationCell: ConfigurableCell { + func configure(object: Location) { + name.text = object.name + coordinates.text = String("\(object.latitude) \(object.longitude)") + } +} diff --git a/Container/Container-code/Container/LocationDataSource.swift b/Container/Container-code/Container/LocationDataSource.swift new file mode 100644 index 0000000..96ac6e3 --- /dev/null +++ b/Container/Container-code/Container/LocationDataSource.swift @@ -0,0 +1,88 @@ +// +// LocationDataSource.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LocationDataSource: NSObject { + + private let tableView: UITableView + private var locations = [Location]() + + init(tableView: UITableView, from path: String) { + self.tableView = tableView + super.init() + readFromPlist(name: path) + tableView.dataSource = self + tableView.reloadData() + } + + func locationAtIndexPath(_ indexPath: IndexPath) -> Location? { + return indexPath.row < locations.count ? locations[indexPath.row] : nil + } + + private func readFromPlist(name: String) { + guard let items = NSArray(contentsOfFile: name) as? [Dictionary] else { + return + } + for item in items { + if let location = Location(dictionary: item) { + locations.append(location) + } + } + } +} + +extension LocationDataSource: UITableViewDataSource { + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return locations.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: LocationCell.reuseIdentifier, for: indexPath) + configure(cell: cell, indexPath: indexPath) + return cell + } + + private func configure(cell: UITableViewCell, indexPath: IndexPath) { + if let cell = cell as? LocationCell { + let object = locations[indexPath.row] + cell.configure(object: object) + } + } +} + diff --git a/Container/Container-code/Container/LocationTableViewController.swift b/Container/Container-code/Container/LocationTableViewController.swift new file mode 100644 index 0000000..18f743c --- /dev/null +++ b/Container/Container-code/Container/LocationTableViewController.swift @@ -0,0 +1,62 @@ +// +// LocationTableViewController.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol LocationProviderDelegate: AnyObject { + func didSelectLocation(_ location: Location) +} + +final class LocationTableViewController: UITableViewController { + weak var delegate: LocationProviderDelegate? + + private var locationDataSource: LocationDataSource? + + override func viewDidLoad() { + super.viewDidLoad() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = UITableView.automaticDimension + tableView.delegate = self + + if let plistPath = Bundle.main.path(forResource: "locations", ofType: "plist") { + locationDataSource = LocationDataSource(tableView: tableView, from: plistPath) + tableView.dataSource = locationDataSource + } + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if let location = locationDataSource?.locationAtIndexPath(indexPath) { + delegate?.didSelectLocation(location) + } + } +} diff --git a/Container/Container-code/Container/MapViewController.swift b/Container/Container-code/Container/MapViewController.swift new file mode 100644 index 0000000..692137e --- /dev/null +++ b/Container/Container-code/Container/MapViewController.swift @@ -0,0 +1,90 @@ +// +// MapViewController.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import MapKit +import UIKit + +final class MapViewController: UIViewController { + @IBOutlet private var mapView: MKMapView! + + /// The zoom level to use when setting the span + /// of the map region to show. Default is 10 degrees. + + var zoom: CLLocationDegrees = 10.0 + + /// The coordinate to center the map on. Setting a new + /// coordinate centers the map on a region spanned by + /// the `zoom` level and drops a pin annotation at the + /// coordinate. + + var coordinate: CLLocationCoordinate2D? { + didSet { + if let coordinate = coordinate { + centerMap(coordinate) + annotate(coordinate) + } + } + } + + private func centerMap(_ coordinate: CLLocationCoordinate2D) { + let span = MKCoordinateSpan(latitudeDelta: zoom, longitudeDelta: zoom) + let region = MKCoordinateRegion(center: coordinate, span: span) + mapView.setRegion(region, animated: true) + } + + private func annotate(_ coordinate: CLLocationCoordinate2D) { + let annotation = MKPointAnnotation() + annotation.coordinate = coordinate + mapView.addAnnotation(annotation) + } +} + +extension MapViewController: MKMapViewDelegate { + private enum AnnotationView: String { + case pin = "Pin" + } + + func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { + guard let annotation = annotation as? MKPointAnnotation else { + return nil + } + + let identifier = AnnotationView.pin.rawValue + guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView else { + return MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) + } + + annotationView.annotation = annotation + return annotationView + } +} diff --git a/Container/Container-code/Container/MasterViewController.swift b/Container/Container-code/Container/MasterViewController.swift new file mode 100644 index 0000000..dde0d93 --- /dev/null +++ b/Container/Container-code/Container/MasterViewController.swift @@ -0,0 +1,104 @@ +// +// MasterViewController.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class MasterViewController: UIViewController { + private let topStackView = UIStackView() + + private lazy var locationTableViewController: LocationTableViewController = self.buildFromStoryboard("Main") + private lazy var mapViewController: MapViewController = self.buildFromStoryboard("Main") + + override func viewDidLoad() { + super.viewDidLoad() + setupStackView() + + addContentController(locationTableViewController, to: topStackView) + addContentController(mapViewController, to: topStackView) + locationTableViewController.delegate = self + } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + topStackView.axis = axisForSize(view.bounds.size) + } + + private func addContentController(_ child: UIViewController, to stackView: UIStackView) { + addChild(child) + stackView.addArrangedSubview(child.view) + child.didMove(toParent: self) + } + + private func removeContentController(_ child: UIViewController, from stackView: UIStackView) { + child.willMove(toParent: nil) + stackView.removeArrangedSubview(child.view) + child.view.removeFromSuperview() + child.removeFromParent() + } + + private func setupStackView() { + topStackView.alignment = .fill + topStackView.distribution = .fillEqually + topStackView.spacing = 8.0 + + topStackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(topStackView) + + let margins = view.layoutMarginsGuide + NSLayoutConstraint.activate([ + topStackView.leadingAnchor.constraint(equalTo: margins.leadingAnchor), + topStackView.trailingAnchor.constraint(equalTo: margins.trailingAnchor), + topStackView.topAnchor.constraint(equalTo: margins.topAnchor), + topStackView.bottomAnchor.constraint(equalTo: margins.bottomAnchor) + ]) + } + + private func axisForSize(_ size: CGSize) -> NSLayoutConstraint.Axis { + return size.width > size.height ? .horizontal : .vertical + } + + private func buildFromStoryboard(_ name: String) -> T { + let storyboard = UIStoryboard(name: name, bundle: nil) + let identifier = String(describing: T.self) + guard let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as? T else { + fatalError("Missing \(identifier) in Storyboard") + } + return viewController + } +} + +extension MasterViewController: LocationProviderDelegate { + func didSelectLocation(_ location: Location) { + mapViewController.coordinate = location.coordinate + } +} diff --git a/Container/Container-code/Container/ReusableIdentifier.swift b/Container/Container-code/Container/ReusableIdentifier.swift new file mode 100644 index 0000000..893e7f4 --- /dev/null +++ b/Container/Container-code/Container/ReusableIdentifier.swift @@ -0,0 +1,43 @@ +// +// ReusableIdentifier.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ReusableIdentifier: class { + static var reuseIdentifier: String { get } +} + +extension ReusableIdentifier { + static var reuseIdentifier: String { + return "\(self)" + } +} diff --git a/Container/Container-code/Container/locations.plist b/Container/Container-code/Container/locations.plist new file mode 100644 index 0000000..1d4ad3c --- /dev/null +++ b/Container/Container-code/Container/locations.plist @@ -0,0 +1,247 @@ +( +{name="Afghanistan";latitude="33.93911";longitude="67.709953";}, +{name="Albania";latitude="41.153332";longitude="20.168331";}, +{name="Algeria";latitude="28.033886";longitude="1.659626";}, +{name="American Samoa";latitude="-14.270972";longitude="-170.132217";}, +{name="Andorra";latitude="42.546245";longitude="1.601554";}, +{name="Angola";latitude="-11.202692";longitude="17.873887";}, +{name="Anguilla";latitude="18.220554";longitude="-63.068615";}, +{name="Antarctica";latitude="-75.250973";longitude="-0.071389";}, +{name="Antigua and Barbuda";latitude="17.060816";longitude="-61.796428";}, +{name="Argentina";latitude="-38.416097";longitude="-63.616672";}, +{name="Armenia";latitude="40.069099";longitude="45.038189";}, +{name="Aruba";latitude="12.52111";longitude="-69.968338";}, +{name="Australia";latitude="-25.274398";longitude="133.775136";}, +{name="Austria";latitude="47.516231";longitude="14.550072";}, +{name="Azerbaijan";latitude="40.143105";longitude="47.576927";}, +{name="Bahamas";latitude="25.03428";longitude="-77.39628";}, +{name="Bahrain";latitude="25.930414";longitude="50.637772";}, +{name="Bangladesh";latitude="23.684994";longitude="90.356331";}, +{name="Barbados";latitude="13.193887";longitude="-59.543198";}, +{name="Belarus";latitude="53.709807";longitude="27.953389";}, +{name="Belgium";latitude="50.503887";longitude="4.469936";}, +{name="Belize";latitude="17.189877";longitude="-88.49765";}, +{name="Benin";latitude="9.30769";longitude="2.315834";}, +{name="Bermuda";latitude="32.321384";longitude="-64.75737";}, +{name="Bhutan";latitude="27.514162";longitude="90.433601";}, +{name="Bolivia";latitude="-16.290154";longitude="-63.588653";}, +{name="Bosnia and Herzegovina";latitude="43.915886";longitude="17.679076";}, +{name="Botswana";latitude="-22.328474";longitude="24.684866";}, +{name="Bouvet Island";latitude="-54.423199";longitude="3.413194";}, +{name="Brazil";latitude="-14.235004";longitude="-51.92528";}, +{name="British Indian Ocean Territory";latitude="-6.343194";longitude="71.876519";}, +{name="British Virgin Islands";latitude="18.420695";longitude="-64.639968";}, +{name="Brunei";latitude="4.535277";longitude="114.727669";}, +{name="Bulgaria";latitude="42.733883";longitude="25.48583";}, +{name="Burkina Faso";latitude="12.238333";longitude="-1.561593";}, +{name="Burundi";latitude="-3.373056";longitude="29.918886";}, +{name="Cambodia";latitude="12.565679";longitude="104.990963";}, +{name="Cameroon";latitude="7.369722";longitude="12.354722";}, +{name="Canada";latitude="56.130366";longitude="-106.346771";}, +{name="Cape Verde";latitude="16.002082";longitude="-24.013197";}, +{name="Cayman Islands";latitude="19.513469";longitude="-80.566956";}, +{name="Central African Republic";latitude="6.611111";longitude="20.939444";}, +{name="Chad";latitude="15.454166";longitude="18.732207";}, +{name="Chile";latitude="-35.675147";longitude="-71.542969";}, +{name="China";latitude="35.86166";longitude="104.195397";}, +{name="Christmas Island";latitude="-10.447525";longitude="105.690449";}, +{name="Cocos [Keeling] Islands";latitude="-12.164165";longitude="96.870956";}, +{name="Colombia";latitude="4.570868";longitude="-74.297333";}, +{name="Comoros";latitude="-11.875001";longitude="43.872219";}, +{name="Congo [DRC]";latitude="-4.038333";longitude="21.758664";}, +{name="Congo [Republic]";latitude="-0.228021";longitude="15.827659";}, +{name="Cook Islands";latitude="-21.236736";longitude="-159.777671";}, +{name="Costa Rica";latitude="9.748917";longitude="-83.753428";}, +{name="Croatia";latitude="45.1";longitude="15.2";}, +{name="Cuba";latitude="21.521757";longitude="-77.781167";}, +{name="Cyprus";latitude="35.126413";longitude="33.429859";}, +{name="Czech Republic";latitude="49.817492";longitude="15.472962";}, +{name="Côte d'Ivoire";latitude="7.539989";longitude="-5.54708";}, +{name="Denmark";latitude="56.26392";longitude="9.501785";}, +{name="Djibouti";latitude="11.825138";longitude="42.590275";}, +{name="Dominica";latitude="15.414999";longitude="-61.370976";}, +{name="Dominican Republic";latitude="18.735693";longitude="-70.162651";}, +{name="Ecuador";latitude="-1.831239";longitude="-78.183406";}, +{name="Egypt";latitude="26.820553";longitude="30.802498";}, +{name="El Salvador";latitude="13.794185";longitude="-88.89653";}, +{name="Equatorial Guinea";latitude="1.650801";longitude="10.267895";}, +{name="Eritrea";latitude="15.179384";longitude="39.782334";}, +{name="Estonia";latitude="58.595272";longitude="25.013607";}, +{name="Ethiopia";latitude="9.145";longitude="40.489673";}, +{name="Falkland Islands [Islas Malvinas]";latitude="-51.796253";longitude="-59.523613";}, +{name="Faroe Islands";latitude="61.892635";longitude="-6.911806";}, +{name="Fiji";latitude="-16.578193";longitude="179.414413";}, +{name="Finland";latitude="61.92411";longitude="25.748151";}, +{name="France";latitude="46.227638";longitude="2.213749";}, +{name="French Guiana";latitude="3.933889";longitude="-53.125782";}, +{name="French Polynesia";latitude="-17.679742";longitude="-149.406843";}, +{name="French Southern Territories";latitude="-49.280366";longitude="69.348557";}, +{name="Gabon";latitude="-0.803689";longitude="11.609444";}, +{name="Gambia";latitude="13.443182";longitude="-15.310139";}, +{name="Gaza Strip";latitude="31.354676";longitude="34.308825";}, +{name="Georgia";latitude="42.315407";longitude="43.356892";}, +{name="Germany";latitude="51.165691";longitude="10.451526";}, +{name="Ghana";latitude="7.946527";longitude="-1.023194";}, +{name="Gibraltar";latitude="36.137741";longitude="-5.345374";}, +{name="Greece";latitude="39.074208";longitude="21.824312";}, +{name="Greenland";latitude="71.706936";longitude="-42.604303";}, +{name="Grenada";latitude="12.262776";longitude="-61.604171";}, +{name="Guadeloupe";latitude="16.995971";longitude="-62.067641";}, +{name="Guam";latitude="13.444304";longitude="144.793731";}, +{name="Guatemala";latitude="15.783471";longitude="-90.230759";}, +{name="Guernsey";latitude="49.465691";longitude="-2.585278";}, +{name="Guinea";latitude="9.945587";longitude="-9.696645";}, +{name="Guinea-Bissau";latitude="11.803749";longitude="-15.180413";}, +{name="Guyana";latitude="4.860416";longitude="-58.93018";}, +{name="Haiti";latitude="18.971187";longitude="-72.285215";}, +{name="Heard Island and McDonald Islands";latitude="-53.08181";longitude="73.504158";}, +{name="Honduras";latitude="15.199999";longitude="-86.241905";}, +{name="Hong Kong";latitude="22.396428";longitude="114.109497";}, +{name="Hungary";latitude="47.162494";longitude="19.503304";}, +{name="Iceland";latitude="64.963051";longitude="-19.020835";}, +{name="India";latitude="20.593684";longitude="78.96288";}, +{name="Indonesia";latitude="-0.789275";longitude="113.921327";}, +{name="Iran";latitude="32.427908";longitude="53.688046";}, +{name="Iraq";latitude="33.223191";longitude="43.679291";}, +{name="Ireland";latitude="53.41291";longitude="-8.24389";}, +{name="Isle of Man";latitude="54.236107";longitude="-4.548056";}, +{name="Israel";latitude="31.046051";longitude="34.851612";}, +{name="Italy";latitude="41.87194";longitude="12.56738";}, +{name="Jamaica";latitude="18.109581";longitude="-77.297508";}, +{name="Japan";latitude="36.204824";longitude="138.252924";}, +{name="Jersey";latitude="49.214439";longitude="-2.13125";}, +{name="Jordan";latitude="30.585164";longitude="36.238414";}, +{name="Kazakhstan";latitude="48.019573";longitude="66.923684";}, +{name="Kenya";latitude="-0.023559";longitude="37.906193";}, +{name="Kiribati";latitude="-3.370417";longitude="-168.734039";}, +{name="Kosovo";latitude="42.602636";longitude="20.902977";}, +{name="Kuwait";latitude="29.31166";longitude="47.481766";}, +{name="Kyrgyzstan";latitude="41.20438";longitude="74.766098";}, +{name="Laos";latitude="19.85627";longitude="102.495496";}, +{name="Latvia";latitude="56.879635";longitude="24.603189";}, +{name="Lebanon";latitude="33.854721";longitude="35.862285";}, +{name="Lesotho";latitude="-29.609988";longitude="28.233608";}, +{name="Liberia";latitude="6.428055";longitude="-9.429499";}, +{name="Libya";latitude="26.3351";longitude="17.228331";}, +{name="Liechtenstein";latitude="47.166";longitude="9.555373";}, +{name="Lithuania";latitude="55.169438";longitude="23.881275";}, +{name="Luxembourg";latitude="49.815273";longitude="6.129583";}, +{name="Macau";latitude="22.198745";longitude="113.543873";}, +{name="Macedonia [FYROM]";latitude="41.608635";longitude="21.745275";}, +{name="Madagascar";latitude="-18.766947";longitude="46.869107";}, +{name="Malawi";latitude="-13.254308";longitude="34.301525";}, +{name="Malaysia";latitude="4.210484";longitude="101.975766";}, +{name="Maldives";latitude="3.202778";longitude="73.22068";}, +{name="Mali";latitude="17.570692";longitude="-3.996166";}, +{name="Malta";latitude="35.937496";longitude="14.375416";}, +{name="Marshall Islands";latitude="7.131474";longitude="171.184478";}, +{name="Martinique";latitude="14.641528";longitude="-61.024174";}, +{name="Mauritania";latitude="21.00789";longitude="-10.940835";}, +{name="Mauritius";latitude="-20.348404";longitude="57.552152";}, +{name="Mayotte";latitude="-12.8275";longitude="45.166244";}, +{name="Mexico";latitude="23.634501";longitude="-102.552784";}, +{name="Micronesia";latitude="7.425554";longitude="150.550812";}, +{name="Moldova";latitude="47.411631";longitude="28.369885";}, +{name="Monaco";latitude="43.750298";longitude="7.412841";}, +{name="Mongolia";latitude="46.862496";longitude="103.846656";}, +{name="Montenegro";latitude="42.708678";longitude="19.37439";}, +{name="Montserrat";latitude="16.742498";longitude="-62.187366";}, +{name="Morocco";latitude="31.791702";longitude="-7.09262";}, +{name="Mozambique";latitude="-18.665695";longitude="35.529562";}, +{name="Myanmar [Burma]";latitude="21.913965";longitude="95.956223";}, +{name="Namibia";latitude="-22.95764";longitude="18.49041";}, +{name="Nauru";latitude="-0.522778";longitude="166.931503";}, +{name="Nepal";latitude="28.394857";longitude="84.124008";}, +{name="Netherlands Antilles";latitude="12.226079";longitude="-69.060087";}, +{name="Netherlands";latitude="52.132633";longitude="5.291266";}, +{name="New Caledonia";latitude="-20.904305";longitude="165.618042";}, +{name="New Zealand";latitude="-40.900557";longitude="174.885971";}, +{name="Nicaragua";latitude="12.865416";longitude="-85.207229";}, +{name="Niger";latitude="17.607789";longitude="8.081666";}, +{name="Nigeria";latitude="9.081999";longitude="8.675277";}, +{name="Niue";latitude="-19.054445";longitude="-169.867233";}, +{name="Norfolk Island";latitude="-29.040835";longitude="167.954712";}, +{name="North Korea";latitude="40.339852";longitude="127.510093";}, +{name="Northern Mariana Islands";latitude="17.33083";longitude="145.38469";}, +{name="Norway";latitude="60.472024";longitude="8.468946";}, +{name="Oman";latitude="21.512583";longitude="55.923255";}, +{name="Pakistan";latitude="30.375321";longitude="69.345116";}, +{name="Palau";latitude="7.51498";longitude="134.58252";}, +{name="Palestinian Territories";latitude="31.952162";longitude="35.233154";}, +{name="Panama";latitude="8.537981";longitude="-80.782127";}, +{name="Papua New Guinea";latitude="-6.314993";longitude="143.95555";}, +{name="Paraguay";latitude="-23.442503";longitude="-58.443832";}, +{name="Peru";latitude="-9.189967";longitude="-75.015152";}, +{name="Philippines";latitude="12.879721";longitude="121.774017";}, +{name="Pitcairn Islands";latitude="-24.703615";longitude="-127.439308";}, +{name="Poland";latitude="51.919438";longitude="19.145136";}, +{name="Portugal";latitude="39.399872";longitude="-8.224454";}, +{name="Puerto Rico";latitude="18.220833";longitude="-66.590149";}, +{name="Qatar";latitude="25.354826";longitude="51.183884";}, +{name="Romania";latitude="45.943161";longitude="24.96676";}, +{name="Russia";latitude="61.52401";longitude="105.318756";}, +{name="Rwanda";latitude="-1.940278";longitude="29.873888";}, +{name="Réunion";latitude="-21.115141";longitude="55.536384";}, +{name="Saint Helena";latitude="-24.143474";longitude="-10.030696";}, +{name="Saint Kitts and Nevis";latitude="17.357822";longitude="-62.782998";}, +{name="Saint Lucia";latitude="13.909444";longitude="-60.978893";}, +{name="Saint Pierre and Miquelon";latitude="46.941936";longitude="-56.27111";}, +{name="Saint Vincent and the Grenadines";latitude="12.984305";longitude="-61.287228";}, +{name="Samoa";latitude="-13.759029";longitude="-172.104629";}, +{name="San Marino";latitude="43.94236";longitude="12.457777";}, +{name="Saudi Arabia";latitude="23.885942";longitude="45.079162";}, +{name="Senegal";latitude="14.497401";longitude="-14.452362";}, +{name="Serbia";latitude="44.016521";longitude="21.005859";}, +{name="Seychelles";latitude="-4.679574";longitude="55.491977";}, +{name="Sierra Leone";latitude="8.460555";longitude="-11.779889";}, +{name="Singapore";latitude="1.352083";longitude="103.819836";}, +{name="Slovakia";latitude="48.669026";longitude="19.699024";}, +{name="Slovenia";latitude="46.151241";longitude="14.995463";}, +{name="Solomon Islands";latitude="-9.64571";longitude="160.156194";}, +{name="Somalia";latitude="5.152149";longitude="46.199616";}, +{name="South Africa";latitude="-30.559482";longitude="22.937506";}, +{name="South Georgia and the South Sandwich Islands";latitude="-54.429579";longitude="-36.587909";}, +{name="South Korea";latitude="35.907757";longitude="127.766922";}, +{name="Spain";latitude="40.463667";longitude="-3.74922";}, +{name="Sri Lanka";latitude="7.873054";longitude="80.771797";}, +{name="Sudan";latitude="12.862807";longitude="30.217636";}, +{name="Suriname";latitude="3.919305";longitude="-56.027783";}, +{name="Svalbard and Jan Mayen";latitude="77.553604";longitude="23.670272";}, +{name="Swaziland";latitude="-26.522503";longitude="31.465866";}, +{name="Sweden";latitude="60.128161";longitude="18.643501";}, +{name="Switzerland";latitude="46.818188";longitude="8.227512";}, +{name="Syria";latitude="34.802075";longitude="38.996815";}, +{name="São Tomé and Príncipe";latitude="0.18636";longitude="6.613081";}, +{name="Taiwan";latitude="23.69781";longitude="120.960515";}, +{name="Tajikistan";latitude="38.861034";longitude="71.276093";}, +{name="Tanzania";latitude="-6.369028";longitude="34.888822";}, +{name="Thailand";latitude="15.870032";longitude="100.992541";}, +{name="Timor-Leste";latitude="-8.874217";longitude="125.727539";}, +{name="Togo";latitude="8.619543";longitude="0.824782";}, +{name="Tokelau";latitude="-8.967363";longitude="-171.855881";}, +{name="Tonga";latitude="-21.178986";longitude="-175.198242";}, +{name="Trinidad and Tobago";latitude="10.691803";longitude="-61.222503";}, +{name="Tunisia";latitude="33.886917";longitude="9.537499";}, +{name="Turkey";latitude="38.963745";longitude="35.243322";}, +{name="Turkmenistan";latitude="38.969719";longitude="59.556278";}, +{name="Turks and Caicos Islands";latitude="21.694025";longitude="-71.797928";}, +{name="Tuvalu";latitude="-7.109535";longitude="177.64933";}, +{name="U.S. Minor Outlying Islands";latitude="";longitude="";}, +{name="U.S. Virgin Islands";latitude="18.335765";longitude="-64.896335";}, +{name="Uganda";latitude="1.373333";longitude="32.290275";}, +{name="Ukraine";latitude="48.379433";longitude="31.16558";}, +{name="United Arab Emirates";latitude="23.424076";longitude="53.847818";}, +{name="United Kingdom";latitude="55.378051";longitude="-3.435973";}, +{name="United States";latitude="37.09024";longitude="-95.712891";}, +{name="Uruguay";latitude="-32.522779";longitude="-55.765835";}, +{name="Uzbekistan";latitude="41.377491";longitude="64.585262";}, +{name="Vanuatu";latitude="-15.376706";longitude="166.959158";}, +{name="Vatican City";latitude="41.902916";longitude="12.453389";}, +{name="Venezuela";latitude="6.42375";longitude="-66.58973";}, +{name="Vietnam";latitude="14.058324";longitude="108.277199";}, +{name="Wallis and Futuna";latitude="-13.768752";longitude="-177.156097";}, +{name="Western Sahara";latitude="24.215527";longitude="-12.885834";}, +{name="Yemen";latitude="15.552727";longitude="48.516388";}, +{name="Zambia";latitude="-13.133897";longitude="27.849332";}, +{name="Zimbabwe";latitude="-19.015438";longitude="29.154857";} +) diff --git a/Container/Container-code/ContainerTests/Info.plist b/Container/Container-code/ContainerTests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/Container/Container-code/ContainerTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Container/Container-code/ContainerTests/LocationTests.swift b/Container/Container-code/ContainerTests/LocationTests.swift new file mode 100644 index 0000000..93179fa --- /dev/null +++ b/Container/Container-code/ContainerTests/LocationTests.swift @@ -0,0 +1,105 @@ +// +// LocationTests.swift +// Container +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import XCTest +import CoreLocation + +@testable import Container + +class LocationTests: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testInitFromDictionary() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "135"]) + XCTAssertNotNil(australia) + XCTAssert(australia?.name == "Australia") + XCTAssert(australia?.latitude == -25.0) + XCTAssert(australia?.longitude == 135.0) + } + + func testMissingName() { + let australia = Location(dictionary: ["latitude" : "-25", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testMissingLatitude() { + let australia = Location(dictionary: ["name" : "Australis", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testMissingLongitude() { + let australia = Location(dictionary: ["name" : "Australis", + "latitude" : "-25"]) + XCTAssertNil(australia) + } + + func testExtraKeysIgnored() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "135", + "capital" : "Canberra"]) + XCTAssertNotNil(australia) + } + + func testInvalidLatitude() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "hello", + "longitude" : "135"]) + XCTAssertNil(australia) + } + + func testInvalidLongitude() { + let australia = Location(dictionary: ["name" : "Australia", + "latitude" : "-25", + "longitude" : "12a"]) + XCTAssertNil(australia) + } + + func testInvalidCoordinare() { + let nowhere = Location(dictionary: ["name" : "OffTheGrid", + "latitude" : "-100", + "longitude" : "200"]) + XCTAssertNil(nowhere) + } +} diff --git a/Container/Container-code/README.md b/Container/Container-code/README.md new file mode 100644 index 0000000..ce4638f --- /dev/null +++ b/Container/Container-code/README.md @@ -0,0 +1,6 @@ +### Attribution + +The country location data used in this example is based on work created and [shared by Google](https://developers.google.com/readme/policies/) and used according to terms described in [Creative Commons 3.0 Attribution License](http://creativecommons.org/licenses/by/3.0/). + +See the [original source page](https://developers.google.com/public-data/docs/canonical/countries_csv) for details. + diff --git a/Container/README.md b/Container/README.md new file mode 100644 index 0000000..f4d5777 --- /dev/null +++ b/Container/README.md @@ -0,0 +1,14 @@ +### Container + +Example of using view containment to avoid massive view controllers. This folder contains two Xcode projects: + ++ Container-SB: Implements everything with a Storyboard. ++ Container-code: Manages the child views in code. + +#### Further Information + ++ [Container View Controllers](https://useyourloaf.com/blog/container-view-controllers/) + +#### Version History + ++ Version 1.0 26 Feb 2017 Initial release diff --git a/DarkTheme/DarkTheme.xcodeproj/project.pbxproj b/DarkTheme/DarkTheme.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6940263 --- /dev/null +++ b/DarkTheme/DarkTheme.xcodeproj/project.pbxproj @@ -0,0 +1,357 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 535DFF62241589FD00DF6476 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF61241589FD00DF6476 /* AppDelegate.swift */; }; + 535DFF64241589FD00DF6476 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF63241589FD00DF6476 /* SceneDelegate.swift */; }; + 535DFF6B241589FD00DF6476 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 535DFF69241589FD00DF6476 /* Main.storyboard */; }; + 535DFF6D24158A0100DF6476 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 535DFF6C24158A0100DF6476 /* Assets.xcassets */; }; + 535DFF7024158A0100DF6476 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 535DFF6E24158A0100DF6476 /* LaunchScreen.storyboard */; }; + 535DFF7824158B3E00DF6476 /* ThemeTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF7724158B3E00DF6476 /* ThemeTableViewController.swift */; }; + 535DFF7A24158B8E00DF6476 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF7924158B8E00DF6476 /* TextViewController.swift */; }; + 535DFF7C241597CA00DF6476 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF7B241597CA00DF6476 /* Theme.swift */; }; + 535DFF7E2415996900DF6476 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535DFF7D2415996900DF6476 /* Settings.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 535DFF5E241589FD00DF6476 /* DarkTheme.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DarkTheme.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 535DFF61241589FD00DF6476 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 535DFF63241589FD00DF6476 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 535DFF6A241589FD00DF6476 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 535DFF6C24158A0100DF6476 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 535DFF6F24158A0100DF6476 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 535DFF7124158A0100DF6476 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 535DFF7724158B3E00DF6476 /* ThemeTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeTableViewController.swift; sourceTree = ""; }; + 535DFF7924158B8E00DF6476 /* TextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewController.swift; sourceTree = ""; }; + 535DFF7B241597CA00DF6476 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; + 535DFF7D2415996900DF6476 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; + 535DFF7F2416A58B00DF6476 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 535DFF5B241589FD00DF6476 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 535DFF55241589FD00DF6476 = { + isa = PBXGroup; + children = ( + 535DFF7F2416A58B00DF6476 /* README.md */, + 535DFF60241589FD00DF6476 /* DarkTheme */, + 535DFF5F241589FD00DF6476 /* Products */, + ); + sourceTree = ""; + }; + 535DFF5F241589FD00DF6476 /* Products */ = { + isa = PBXGroup; + children = ( + 535DFF5E241589FD00DF6476 /* DarkTheme.app */, + ); + name = Products; + sourceTree = ""; + }; + 535DFF60241589FD00DF6476 /* DarkTheme */ = { + isa = PBXGroup; + children = ( + 535DFF7724158B3E00DF6476 /* ThemeTableViewController.swift */, + 535DFF7B241597CA00DF6476 /* Theme.swift */, + 535DFF7D2415996900DF6476 /* Settings.swift */, + 535DFF7924158B8E00DF6476 /* TextViewController.swift */, + 535DFF61241589FD00DF6476 /* AppDelegate.swift */, + 535DFF63241589FD00DF6476 /* SceneDelegate.swift */, + 535DFF69241589FD00DF6476 /* Main.storyboard */, + 535DFF6C24158A0100DF6476 /* Assets.xcassets */, + 535DFF6E24158A0100DF6476 /* LaunchScreen.storyboard */, + 535DFF7124158A0100DF6476 /* Info.plist */, + ); + path = DarkTheme; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 535DFF5D241589FD00DF6476 /* DarkTheme */ = { + isa = PBXNativeTarget; + buildConfigurationList = 535DFF7424158A0100DF6476 /* Build configuration list for PBXNativeTarget "DarkTheme" */; + buildPhases = ( + 535DFF5A241589FD00DF6476 /* Sources */, + 535DFF5B241589FD00DF6476 /* Frameworks */, + 535DFF5C241589FD00DF6476 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DarkTheme; + productName = DarkTheme; + productReference = 535DFF5E241589FD00DF6476 /* DarkTheme.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 535DFF56241589FD00DF6476 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1140; + LastUpgradeCheck = 1140; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 535DFF5D241589FD00DF6476 = { + CreatedOnToolsVersion = 11.4; + }; + }; + }; + buildConfigurationList = 535DFF59241589FD00DF6476 /* Build configuration list for PBXProject "DarkTheme" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 535DFF55241589FD00DF6476; + productRefGroup = 535DFF5F241589FD00DF6476 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 535DFF5D241589FD00DF6476 /* DarkTheme */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 535DFF5C241589FD00DF6476 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 535DFF7024158A0100DF6476 /* LaunchScreen.storyboard in Resources */, + 535DFF6D24158A0100DF6476 /* Assets.xcassets in Resources */, + 535DFF6B241589FD00DF6476 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 535DFF5A241589FD00DF6476 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 535DFF7E2415996900DF6476 /* Settings.swift in Sources */, + 535DFF7824158B3E00DF6476 /* ThemeTableViewController.swift in Sources */, + 535DFF62241589FD00DF6476 /* AppDelegate.swift in Sources */, + 535DFF7C241597CA00DF6476 /* Theme.swift in Sources */, + 535DFF64241589FD00DF6476 /* SceneDelegate.swift in Sources */, + 535DFF7A24158B8E00DF6476 /* TextViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 535DFF69241589FD00DF6476 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 535DFF6A241589FD00DF6476 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 535DFF6E24158A0100DF6476 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 535DFF6F24158A0100DF6476 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 535DFF7224158A0100DF6476 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 535DFF7324158A0100DF6476 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 535DFF7524158A0100DF6476 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DarkTheme/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DarkTheme; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 535DFF7624158A0100DF6476 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DarkTheme/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DarkTheme; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 535DFF59241589FD00DF6476 /* Build configuration list for PBXProject "DarkTheme" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 535DFF7224158A0100DF6476 /* Debug */, + 535DFF7324158A0100DF6476 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 535DFF7424158A0100DF6476 /* Build configuration list for PBXNativeTarget "DarkTheme" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 535DFF7524158A0100DF6476 /* Debug */, + 535DFF7624158A0100DF6476 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 535DFF56241589FD00DF6476 /* Project object */; +} diff --git a/DarkTheme/DarkTheme/AppDelegate.swift b/DarkTheme/DarkTheme/AppDelegate.swift new file mode 100644 index 0000000..2d32c08 --- /dev/null +++ b/DarkTheme/DarkTheme/AppDelegate.swift @@ -0,0 +1,34 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { +} diff --git a/DarkTheme/DarkTheme/Assets.xcassets/AppIcon.appiconset/Contents.json b/DarkTheme/DarkTheme/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/DarkTheme/DarkTheme/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DarkTheme/DarkTheme/Assets.xcassets/Contents.json b/DarkTheme/DarkTheme/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/DarkTheme/DarkTheme/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/Contents.json b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/defaultBackground.colorset/Contents.json b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/defaultBackground.colorset/Contents.json new file mode 100644 index 0000000..de36eae --- /dev/null +++ b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/defaultBackground.colorset/Contents.json @@ -0,0 +1,78 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF0", + "green" : "0xF0", + "red" : "0xF0" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x33", + "green" : "0x33", + "red" : "0x33" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "contrast", + "value" : "high" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + }, + { + "appearance" : "contrast", + "value" : "high" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/groupedBackground.colorset/Contents.json b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/groupedBackground.colorset/Contents.json new file mode 100644 index 0000000..3d85e7f --- /dev/null +++ b/DarkTheme/DarkTheme/Assets.xcassets/Dynamic Colors/groupedBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF7", + "green" : "0xF2", + "red" : "0xF2" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x00", + "green" : "0x00", + "red" : "0x00" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DarkTheme/DarkTheme/Base.lproj/LaunchScreen.storyboard b/DarkTheme/DarkTheme/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/DarkTheme/DarkTheme/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DarkTheme/DarkTheme/Base.lproj/Main.storyboard b/DarkTheme/DarkTheme/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e93a726 --- /dev/null +++ b/DarkTheme/DarkTheme/Base.lproj/Main.storyboard @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DarkTheme/DarkTheme/Info.plist b/DarkTheme/DarkTheme/Info.plist new file mode 100644 index 0000000..e7f6f58 --- /dev/null +++ b/DarkTheme/DarkTheme/Info.plist @@ -0,0 +1,74 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/DarkTheme/DarkTheme/SceneDelegate.swift b/DarkTheme/DarkTheme/SceneDelegate.swift new file mode 100644 index 0000000..f5dc8a3 --- /dev/null +++ b/DarkTheme/DarkTheme/SceneDelegate.swift @@ -0,0 +1,39 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + let defaults = UserDefaults.standard + window?.overrideUserInterfaceStyle = defaults.theme.userInterfaceStyle + } +} diff --git a/DarkTheme/DarkTheme/Settings.swift b/DarkTheme/DarkTheme/Settings.swift new file mode 100644 index 0000000..6c54941 --- /dev/null +++ b/DarkTheme/DarkTheme/Settings.swift @@ -0,0 +1,42 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +extension UserDefaults { + var theme: Theme { + get { + register(defaults: [#function: Theme.device.rawValue]) + return Theme(rawValue: integer(forKey: #function)) ?? .device + } + set { + set(newValue.rawValue, forKey: #function) + } + } +} diff --git a/DarkTheme/DarkTheme/TextViewController.swift b/DarkTheme/DarkTheme/TextViewController.swift new file mode 100644 index 0000000..d42d839 --- /dev/null +++ b/DarkTheme/DarkTheme/TextViewController.swift @@ -0,0 +1,48 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class TextViewController: UIViewController { + var text: String? { + didSet { + textView?.text = text + } + } + + @IBOutlet private var textView: UITextView? + + override func viewDidLoad() { + super.viewDidLoad() + text = """ + “Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently. They're not fond of rules. And they have no respect for the status quo. You can quote them, disagree with them, glorify or vilify them. About the only thing you can't do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world, are the ones who do.” + ― Rob Siltanen + """ + } +} diff --git a/DarkTheme/DarkTheme/Theme.swift b/DarkTheme/DarkTheme/Theme.swift new file mode 100644 index 0000000..0aaa910 --- /dev/null +++ b/DarkTheme/DarkTheme/Theme.swift @@ -0,0 +1,49 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +enum Theme: Int { + case device + case light + case dark +} + +extension Theme { + var userInterfaceStyle: UIUserInterfaceStyle { + switch self { + case .device: + return .unspecified + case .light: + return .light + case .dark: + return .dark + } + } +} diff --git a/DarkTheme/DarkTheme/ThemeTableViewController.swift b/DarkTheme/DarkTheme/ThemeTableViewController.swift new file mode 100644 index 0000000..438ad54 --- /dev/null +++ b/DarkTheme/DarkTheme/ThemeTableViewController.swift @@ -0,0 +1,67 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ThemeTableViewController: UITableViewController { + var defaults = UserDefaults.standard + private var theme: Theme { + get { + return defaults.theme + } + set { + defaults.theme = newValue + configureStyle(for: newValue) + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + configureCell(for: theme, checked: true) + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if indexPath.row != theme.rawValue { + configureCell(for: theme, checked: false) + theme = Theme(rawValue: indexPath.row) ?? .device + configureCell(for: theme, checked: true) + } + + tableView.deselectRow(at: indexPath, animated: true) + } + + private func configureCell(for theme: Theme, checked: Bool) { + let cell = tableView.cellForRow(at: IndexPath(row: theme.rawValue, section: 0)) + cell?.accessoryType = checked ? .checkmark : .none + } + + private func configureStyle(for theme: Theme) { + view.window?.overrideUserInterfaceStyle = theme.userInterfaceStyle + } +} diff --git a/DarkTheme/README.md b/DarkTheme/README.md new file mode 100644 index 0000000..180e52d --- /dev/null +++ b/DarkTheme/README.md @@ -0,0 +1,5 @@ +# Overriding Dark Mode + +An example of using `overrideUserInterfaceStyle` (iOS 13) to control the appearance of an App. See the following post for more details: + ++ [Overriding Dark Mode](https://useyourloaf.com/blog/overriding-dark-mode/) diff --git a/Designable/Designable.xcodeproj/project.pbxproj b/Designable/Designable.xcodeproj/project.pbxproj new file mode 100644 index 0000000..53b2c3e --- /dev/null +++ b/Designable/Designable.xcodeproj/project.pbxproj @@ -0,0 +1,504 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53182E3C1B2460D1002D441F /* LevelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53182E3B1B2460D1002D441F /* LevelViewController.m */; }; + 53182E6E1B24F75E002D441F /* LevelView.m in Sources */ = {isa = PBXBuildFile; fileRef = 53182E6D1B24F75E002D441F /* LevelView.m */; }; + 538021F91B20EC3900434436 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 538021F81B20EC3900434436 /* main.m */; }; + 538021FC1B20EC3900434436 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 538021FB1B20EC3900434436 /* AppDelegate.m */; }; + 538022021B20EC3900434436 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 538022001B20EC3900434436 /* Main.storyboard */; }; + 538022041B20EC3900434436 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 538022031B20EC3900434436 /* Images.xcassets */; }; + 538022071B20EC3900434436 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 538022051B20EC3900434436 /* LaunchScreen.xib */; }; + 53C515ED1B2786EE0062905B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C515EC1B2786EE0062905B /* AppDelegate.swift */; }; + 53C515F21B2786EE0062905B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53C515F01B2786EE0062905B /* Main.storyboard */; }; + 53C515F41B2786EE0062905B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53C515F31B2786EE0062905B /* Images.xcassets */; }; + 53C515F71B2786EE0062905B /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53C515F51B2786EE0062905B /* LaunchScreen.xib */; }; + 53C5160B1B2788110062905B /* LevelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C5160A1B2788110062905B /* LevelViewController.swift */; }; + 53C5160D1B2789A40062905B /* LevelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C5160C1B2789A40062905B /* LevelView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 53182E611B24F39F002D441F /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 53182E3A1B2460D1002D441F /* LevelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelViewController.h; sourceTree = ""; }; + 53182E3B1B2460D1002D441F /* LevelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LevelViewController.m; sourceTree = ""; }; + 53182E6C1B24F75E002D441F /* LevelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelView.h; sourceTree = ""; }; + 53182E6D1B24F75E002D441F /* LevelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LevelView.m; sourceTree = ""; }; + 538021F31B20EC3900434436 /* Designable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Designable.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 538021F71B20EC3900434436 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 538021F81B20EC3900434436 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 538021FA1B20EC3900434436 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 538021FB1B20EC3900434436 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 538022011B20EC3900434436 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 538022031B20EC3900434436 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 538022061B20EC3900434436 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 53C515E81B2786ED0062905B /* DesignableSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DesignableSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53C515EB1B2786EE0062905B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53C515EC1B2786EE0062905B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53C515F11B2786EE0062905B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53C515F31B2786EE0062905B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53C515F61B2786EE0062905B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 53C5160A1B2788110062905B /* LevelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelViewController.swift; sourceTree = ""; }; + 53C5160C1B2789A40062905B /* LevelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 538021F01B20EC3900434436 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53C515E51B2786ED0062905B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 538021EA1B20EC3900434436 = { + isa = PBXGroup; + children = ( + 538021F51B20EC3900434436 /* Designable */, + 53C515E91B2786EE0062905B /* DesignableSwift */, + 538021F41B20EC3900434436 /* Products */, + ); + sourceTree = ""; + }; + 538021F41B20EC3900434436 /* Products */ = { + isa = PBXGroup; + children = ( + 538021F31B20EC3900434436 /* Designable.app */, + 53C515E81B2786ED0062905B /* DesignableSwift.app */, + ); + name = Products; + sourceTree = ""; + }; + 538021F51B20EC3900434436 /* Designable */ = { + isa = PBXGroup; + children = ( + 53182E6C1B24F75E002D441F /* LevelView.h */, + 53182E6D1B24F75E002D441F /* LevelView.m */, + 538022001B20EC3900434436 /* Main.storyboard */, + 53182E3A1B2460D1002D441F /* LevelViewController.h */, + 53182E3B1B2460D1002D441F /* LevelViewController.m */, + 538021F61B20EC3900434436 /* Supporting Files */, + ); + path = Designable; + sourceTree = ""; + }; + 538021F61B20EC3900434436 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 538022031B20EC3900434436 /* Images.xcassets */, + 538022051B20EC3900434436 /* LaunchScreen.xib */, + 538021FA1B20EC3900434436 /* AppDelegate.h */, + 538021FB1B20EC3900434436 /* AppDelegate.m */, + 538021F71B20EC3900434436 /* Info.plist */, + 538021F81B20EC3900434436 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53C515E91B2786EE0062905B /* DesignableSwift */ = { + isa = PBXGroup; + children = ( + 53C5160C1B2789A40062905B /* LevelView.swift */, + 53C5160A1B2788110062905B /* LevelViewController.swift */, + 53C515F01B2786EE0062905B /* Main.storyboard */, + 53C515EA1B2786EE0062905B /* Supporting Files */, + ); + path = DesignableSwift; + sourceTree = ""; + }; + 53C515EA1B2786EE0062905B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53C515F51B2786EE0062905B /* LaunchScreen.xib */, + 53C515F31B2786EE0062905B /* Images.xcassets */, + 53C515EC1B2786EE0062905B /* AppDelegate.swift */, + 53C515EB1B2786EE0062905B /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 538021F21B20EC3900434436 /* Designable */ = { + isa = PBXNativeTarget; + buildConfigurationList = 538022161B20EC3A00434436 /* Build configuration list for PBXNativeTarget "Designable" */; + buildPhases = ( + 538021EF1B20EC3900434436 /* Sources */, + 538021F01B20EC3900434436 /* Frameworks */, + 538021F11B20EC3900434436 /* Resources */, + 53182E611B24F39F002D441F /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Designable; + productName = Designable; + productReference = 538021F31B20EC3900434436 /* Designable.app */; + productType = "com.apple.product-type.application"; + }; + 53C515E71B2786ED0062905B /* DesignableSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53C516081B2786EE0062905B /* Build configuration list for PBXNativeTarget "DesignableSwift" */; + buildPhases = ( + 53C515E41B2786ED0062905B /* Sources */, + 53C515E51B2786ED0062905B /* Frameworks */, + 53C515E61B2786ED0062905B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DesignableSwift; + productName = DesignableSwift; + productReference = 53C515E81B2786ED0062905B /* DesignableSwift.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 538021EB1B20EC3900434436 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 538021F21B20EC3900434436 = { + CreatedOnToolsVersion = 6.3.2; + DevelopmentTeam = LCC2J94N44; + }; + 53C515E71B2786ED0062905B = { + CreatedOnToolsVersion = 6.3.2; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 538021EE1B20EC3900434436 /* Build configuration list for PBXProject "Designable" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 538021EA1B20EC3900434436; + productRefGroup = 538021F41B20EC3900434436 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 538021F21B20EC3900434436 /* Designable */, + 53C515E71B2786ED0062905B /* DesignableSwift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 538021F11B20EC3900434436 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 538022021B20EC3900434436 /* Main.storyboard in Resources */, + 538022071B20EC3900434436 /* LaunchScreen.xib in Resources */, + 538022041B20EC3900434436 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53C515E61B2786ED0062905B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53C515F21B2786EE0062905B /* Main.storyboard in Resources */, + 53C515F71B2786EE0062905B /* LaunchScreen.xib in Resources */, + 53C515F41B2786EE0062905B /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 538021EF1B20EC3900434436 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 538021FC1B20EC3900434436 /* AppDelegate.m in Sources */, + 53182E6E1B24F75E002D441F /* LevelView.m in Sources */, + 538021F91B20EC3900434436 /* main.m in Sources */, + 53182E3C1B2460D1002D441F /* LevelViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53C515E41B2786ED0062905B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53C515ED1B2786EE0062905B /* AppDelegate.swift in Sources */, + 53C5160D1B2789A40062905B /* LevelView.swift in Sources */, + 53C5160B1B2788110062905B /* LevelViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 538022001B20EC3900434436 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 538022011B20EC3900434436 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 538022051B20EC3900434436 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 538022061B20EC3900434436 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; + 53C515F01B2786EE0062905B /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53C515F11B2786EE0062905B /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53C515F51B2786EE0062905B /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 53C515F61B2786EE0062905B /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 538022141B20EC3A00434436 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 538022151B20EC3A00434436 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 538022171B20EC3A00434436 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Designable/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 538022181B20EC3A00434436 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Designable/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 53C516041B2786EE0062905B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = DesignableSwift/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53C516051B2786EE0062905B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DesignableSwift/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 538021EE1B20EC3900434436 /* Build configuration list for PBXProject "Designable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 538022141B20EC3A00434436 /* Debug */, + 538022151B20EC3A00434436 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 538022161B20EC3A00434436 /* Build configuration list for PBXNativeTarget "Designable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 538022171B20EC3A00434436 /* Debug */, + 538022181B20EC3A00434436 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53C516081B2786EE0062905B /* Build configuration list for PBXNativeTarget "DesignableSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53C516041B2786EE0062905B /* Debug */, + 53C516051B2786EE0062905B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 538021EB1B20EC3900434436 /* Project object */; +} diff --git a/Designable/Designable/AppDelegate.h b/Designable/Designable/AppDelegate.h new file mode 100644 index 0000000..2086adc --- /dev/null +++ b/Designable/Designable/AppDelegate.h @@ -0,0 +1,42 @@ +// +// AppDelegate.h +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end + diff --git a/Designable/Designable/AppDelegate.m b/Designable/Designable/AppDelegate.m new file mode 100644 index 0000000..31c5ab2 --- /dev/null +++ b/Designable/Designable/AppDelegate.m @@ -0,0 +1,43 @@ +// +// AppDelegate.m +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +@end diff --git a/Designable/Designable/Base.lproj/LaunchScreen.xib b/Designable/Designable/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..3f72a30 --- /dev/null +++ b/Designable/Designable/Base.lproj/LaunchScreen.xib @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Designable/Designable/Base.lproj/Main.storyboard b/Designable/Designable/Base.lproj/Main.storyboard new file mode 100644 index 0000000..5fdf825 --- /dev/null +++ b/Designable/Designable/Base.lproj/Main.storyboard @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Designable/Designable/Images.xcassets/AppIcon.appiconset/Contents.json b/Designable/Designable/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/Designable/Designable/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Designable/Designable/Info.plist b/Designable/Designable/Info.plist new file mode 100644 index 0000000..084f30f --- /dev/null +++ b/Designable/Designable/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.2 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Designable/Designable/LevelView.h b/Designable/Designable/LevelView.h new file mode 100644 index 0000000..c547079 --- /dev/null +++ b/Designable/Designable/LevelView.h @@ -0,0 +1,71 @@ +// +// LevelView.h +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +IB_DESIGNABLE +/** + A custom level view displayed as a horizontal colored bar which + changes color as the level drops below a configurable theshold. + Set the value of the level as a CGFloat between 0.0 and 1.0. + Customise the colors of the bar, the threshold, border width + and border color as required. + */ +@interface LevelView : UIView +/** + The current level value in the range 0.0 - 1.0. Defaults to 1.0. + */ +@property (nonatomic, assign) IBInspectable CGFloat value; +/** + The threshold value in the range 0.0 - 1.0 at which the bar color + changes between emptyColor and fullColor. Default is 0.3. + */ +@property (nonatomic, assign) IBInspectable CGFloat threshold; +/** + The border width for the frame surrounding the bar. Default is 2.0. + */ +@property (nonatomic, assign) IBInspectable CGFloat borderWidth; +/** + The color of the bar border. Default is black. + */ +@property (nonatomic, copy) IBInspectable UIColor *borderColor; +/** + The color of the bar when value >= threshold. Default is green. + */ +@property (nonatomic, copy) IBInspectable UIColor *fullColor; +/** + The color of the bar when value < threshold. Default is red. + */ +@property (nonatomic, copy) IBInspectable UIColor *emptyColor; +@end diff --git a/Designable/Designable/LevelView.m b/Designable/Designable/LevelView.m new file mode 100644 index 0000000..ee9f04d --- /dev/null +++ b/Designable/Designable/LevelView.m @@ -0,0 +1,133 @@ +// +// LevelView.m +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "LevelView.h" + +@interface LevelView () +@property (nonatomic, strong) CAShapeLayer *barLayer; +@end + +@implementation LevelView + +- (void)setupDefaults { + if (self.barLayer == nil) { + self.barLayer = [CAShapeLayer layer]; + [self.layer addSublayer:self.barLayer]; + } + self.value = 1.0f; + self.threshold = 0.3f; + self.borderWidth = 2.0f; + self.borderColor = [UIColor blackColor]; + self.fullColor = [UIColor greenColor]; + self.emptyColor = [UIColor redColor]; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self setupDefaults]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self setupDefaults]; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + [self updateLayerProperties]; +} + +- (void)setValue:(CGFloat)value { + if ((value >= 0.0) && (value <= 1.0)) { + _value = value; + [self updateLayerProperties]; + } +} + +- (void)setThreshold:(CGFloat)threshold { + if ((threshold >= 0.0) && (threshold <= 1.0)) { + _threshold = threshold; + [self updateLayerProperties]; + } +} + +- (void)setBorderWidth:(CGFloat)borderWidth { + if (borderWidth != _borderWidth) { + _borderWidth = borderWidth; + [self updateLayerProperties]; + } +} + +- (void)setBorderColor:(UIColor *)borderColor { + if (borderColor != _borderColor) { + _borderColor = borderColor; + [self updateLayerProperties]; + } +} + +- (void)setFullColor:(UIColor *)fullColor { + if (fullColor != _fullColor) { + _fullColor = fullColor; + [self updateLayerProperties]; + } +} + +- (void)setEmptyColor:(UIColor *)emptyColor { + if (emptyColor != _emptyColor) { + _emptyColor = emptyColor; + [self updateLayerProperties]; + } +} + +- (void)updateLayerProperties { + CGRect barRect = self.bounds; + barRect.size.width = self.bounds.size.width * self.value; + UIBezierPath *path = [UIBezierPath bezierPathWithRect:barRect]; + self.barLayer.path = path.CGPath; + self.barLayer.fillColor = (self.value >= self.threshold) ? self.fullColor.CGColor : self.emptyColor.CGColor; + self.layer.borderWidth = self.borderWidth; + self.layer.borderColor = self.borderColor.CGColor; + self.layer.cornerRadius = 5.0f; + self.layer.masksToBounds = YES; +} + +@end diff --git a/Designable/Designable/LevelViewController.h b/Designable/Designable/LevelViewController.h new file mode 100644 index 0000000..c316545 --- /dev/null +++ b/Designable/Designable/LevelViewController.h @@ -0,0 +1,38 @@ +// +// LevelViewController.h +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +@import UIKit; + +@interface LevelViewController : UIViewController + +@end diff --git a/Designable/Designable/LevelViewController.m b/Designable/Designable/LevelViewController.m new file mode 100644 index 0000000..5f6e87c --- /dev/null +++ b/Designable/Designable/LevelViewController.m @@ -0,0 +1,54 @@ +// +// LevelViewController.m +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "LevelViewController.h" +#import "LevelView.h" + +@interface LevelViewController () +@property (weak, nonatomic) IBOutlet UIStepper *stepper; +@property (weak, nonatomic) IBOutlet LevelView *levelView; +@end + +@implementation LevelViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.stepper.value = self.levelView.value; +} + +- (IBAction)changeValue:(UIStepper *)sender { + self.levelView.value = sender.value; +} + +@end diff --git a/Designable/Designable/main.m b/Designable/Designable/main.m new file mode 100644 index 0000000..7dd983c --- /dev/null +++ b/Designable/Designable/main.m @@ -0,0 +1,42 @@ +// +// main.m +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Designable/DesignableSwift/AppDelegate.swift b/Designable/DesignableSwift/AppDelegate.swift new file mode 100644 index 0000000..416ae9f --- /dev/null +++ b/Designable/DesignableSwift/AppDelegate.swift @@ -0,0 +1,12 @@ +// +// AppDelegate.swift +// DesignableSwift +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} + diff --git a/Designable/DesignableSwift/Base.lproj/LaunchScreen.xib b/Designable/DesignableSwift/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..d37a9b0 --- /dev/null +++ b/Designable/DesignableSwift/Base.lproj/LaunchScreen.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Designable/DesignableSwift/Base.lproj/Main.storyboard b/Designable/DesignableSwift/Base.lproj/Main.storyboard new file mode 100644 index 0000000..831fac8 --- /dev/null +++ b/Designable/DesignableSwift/Base.lproj/Main.storyboard @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Designable/DesignableSwift/Images.xcassets/AppIcon.appiconset/Contents.json b/Designable/DesignableSwift/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/Designable/DesignableSwift/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Designable/DesignableSwift/Info.plist b/Designable/DesignableSwift/Info.plist new file mode 100644 index 0000000..084f30f --- /dev/null +++ b/Designable/DesignableSwift/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.2 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Designable/DesignableSwift/LevelView.swift b/Designable/DesignableSwift/LevelView.swift new file mode 100644 index 0000000..7897fb2 --- /dev/null +++ b/Designable/DesignableSwift/LevelView.swift @@ -0,0 +1,132 @@ +// +// LevelView.swift +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/** + A custom level view displayed as a horizontal colored bar which + changes color as the level drops below a configurable theshold. + Set the value of the level as a CGFloat between 0.0 and 1.0. + Customise the colors of the bar, the threshold, border width + and border color as required. + */ +@IBDesignable +class LevelView: UIView { + /** + The current level value in the range 0.0 - 1.0. Defaults to 1.0. + */ + @IBInspectable var value: CGFloat = 1.0 { + didSet { + updateLayoutProperties() + } + } + + /** + The threshold value in the range 0.0 - 1.0 at which the bar color + changes between emptyColor and fullColor. Default is 0.3. + */ + @IBInspectable var threshold: CGFloat = 0.3 { + didSet { + updateLayoutProperties() + } + } + + /** + The border width for the frame surrounding the bar. Default is 2.0. + */ + @IBInspectable var borderWidth: CGFloat = 2.0 { + didSet { + updateLayoutProperties() + } + } + + /** + The color of the bar border. Default is black. + */ + @IBInspectable var borderColor: UIColor = .black { + didSet { + updateLayoutProperties() + } + } + + /** + The color of the bar when value >= threshold. Default is green. + */ + @IBInspectable var fullColor: UIColor = .green { + didSet { + updateLayoutProperties() + } + } + + /** + The color of the bar when value < threshold. Default is red. + */ + @IBInspectable var emtpyColor: UIColor = .red { + didSet { + updateLayoutProperties() + } + } + + private let barLayer = CAShapeLayer() + + func setup() { + layer.addSublayer(barLayer) + updateLayoutProperties() + } + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + override func layoutSubviews() { + super.layoutSubviews() + updateLayoutProperties() + } + + func updateLayoutProperties() { + let barRect = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width * value, height: bounds.size.height) + let path = UIBezierPath(rect: barRect) + barLayer.path = path.cgPath + barLayer.fillColor = value >= threshold ? fullColor.cgColor : emtpyColor.cgColor + layer.borderWidth = borderWidth + layer.borderColor = borderColor.cgColor + layer.cornerRadius = 5.0 + layer.masksToBounds = true + } +} diff --git a/Designable/DesignableSwift/LevelViewController.swift b/Designable/DesignableSwift/LevelViewController.swift new file mode 100644 index 0000000..1c17279 --- /dev/null +++ b/Designable/DesignableSwift/LevelViewController.swift @@ -0,0 +1,48 @@ +// +// LevelViewController.swift +// Designable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LevelViewController: UIViewController { + @IBOutlet private var levelView: LevelView! + @IBOutlet private var stepper: UIStepper! + + override func viewDidLoad() { + super.viewDidLoad() + stepper.value = Double(levelView.value) + } + + @IBAction func valueChanged(_ sender: UIStepper) { + levelView.value = CGFloat(sender.value) + } +} diff --git a/Designable/README.md b/Designable/README.md new file mode 100644 index 0000000..5baabe5 --- /dev/null +++ b/Designable/README.md @@ -0,0 +1,15 @@ +# Designable - live custom views in Interface Builder + +Example of how to use IB_DESIGNABLE and IBInspectable to preview custom views in Interface Builder. + +## Further Information + +See the following blog post: + ++ [IB_DESIGNABLE Custom Views In Interface Builder](https://useyourloaf.com/blog/ib-designable-custom-views-in-interface-builder/) + +## Version History + ++ Version 1.2 26 Oct 2017 Updated for Xcode 9 and Swift 4 ++ Version 1.1 10 June 2015 Added Swift version ++ Version 1.0 07 June 2015 Initial version. diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer.xcodeproj/project.pbxproj b/DynamicContainer/DynamicContainer-v1/DynamicContainer.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3e407e2 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer.xcodeproj/project.pbxproj @@ -0,0 +1,359 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 53F5583B22315783004115F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5583A22315783004115F3 /* AppDelegate.swift */; }; + 53F5584022315783004115F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F5583E22315783004115F3 /* Main.storyboard */; }; + 53F5584222315784004115F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53F5584122315784004115F3 /* Assets.xcassets */; }; + 53F5584522315784004115F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F5584322315784004115F3 /* LaunchScreen.storyboard */; }; + 53F5584D22316574004115F3 /* BookListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5584C22316574004115F3 /* BookListTableViewController.swift */; }; + 53F5584F2231669B004115F3 /* LibraryContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */; }; + 53F5585122316C99004115F3 /* MessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585022316C99004115F3 /* MessageViewController.swift */; }; + 53F5585322316D55004115F3 /* Book.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585222316D55004115F3 /* Book.swift */; }; + 53F5585522316DBB004115F3 /* SegueHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585422316DBB004115F3 /* SegueHandler.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 535A7A2A2236C513004D643A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53F5583722315783004115F3 /* DynamicContainer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicContainer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53F5583A22315783004115F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53F5583F22315783004115F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53F5584122315784004115F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53F5584422315784004115F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53F5584622315784004115F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53F5584C22316574004115F3 /* BookListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookListTableViewController.swift; sourceTree = ""; }; + 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryContainerViewController.swift; sourceTree = ""; }; + 53F5585022316C99004115F3 /* MessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewController.swift; sourceTree = ""; }; + 53F5585222316D55004115F3 /* Book.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Book.swift; sourceTree = ""; }; + 53F5585422316DBB004115F3 /* SegueHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegueHandler.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53F5583422315783004115F3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53F5582E22315783004115F3 = { + isa = PBXGroup; + children = ( + 535A7A2A2236C513004D643A /* README.md */, + 53F5583922315783004115F3 /* DynamicContainer */, + 53F5583822315783004115F3 /* Products */, + ); + sourceTree = ""; + }; + 53F5583822315783004115F3 /* Products */ = { + isa = PBXGroup; + children = ( + 53F5583722315783004115F3 /* DynamicContainer.app */, + ); + name = Products; + sourceTree = ""; + }; + 53F5583922315783004115F3 /* DynamicContainer */ = { + isa = PBXGroup; + children = ( + 53F5583A22315783004115F3 /* AppDelegate.swift */, + 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */, + 53F5584C22316574004115F3 /* BookListTableViewController.swift */, + 53F5585022316C99004115F3 /* MessageViewController.swift */, + 53F5585422316DBB004115F3 /* SegueHandler.swift */, + 53F5585222316D55004115F3 /* Book.swift */, + 53F5583E22315783004115F3 /* Main.storyboard */, + 53F5584122315784004115F3 /* Assets.xcassets */, + 53F5584322315784004115F3 /* LaunchScreen.storyboard */, + 53F5584622315784004115F3 /* Info.plist */, + ); + path = DynamicContainer; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53F5583622315783004115F3 /* DynamicContainer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53F5584922315784004115F3 /* Build configuration list for PBXNativeTarget "DynamicContainer" */; + buildPhases = ( + 53F5583322315783004115F3 /* Sources */, + 53F5583422315783004115F3 /* Frameworks */, + 53F5583522315783004115F3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DynamicContainer; + productName = DynamicContainer; + productReference = 53F5583722315783004115F3 /* DynamicContainer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53F5582F22315783004115F3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1020; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53F5583622315783004115F3 = { + CreatedOnToolsVersion = 10.2; + }; + }; + }; + buildConfigurationList = 53F5583222315783004115F3 /* Build configuration list for PBXProject "DynamicContainer" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53F5582E22315783004115F3; + productRefGroup = 53F5583822315783004115F3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53F5583622315783004115F3 /* DynamicContainer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53F5583522315783004115F3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F5584522315784004115F3 /* LaunchScreen.storyboard in Resources */, + 53F5584222315784004115F3 /* Assets.xcassets in Resources */, + 53F5584022315783004115F3 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53F5583322315783004115F3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F5585522316DBB004115F3 /* SegueHandler.swift in Sources */, + 53F5584F2231669B004115F3 /* LibraryContainerViewController.swift in Sources */, + 53F5583B22315783004115F3 /* AppDelegate.swift in Sources */, + 53F5585122316C99004115F3 /* MessageViewController.swift in Sources */, + 53F5585322316D55004115F3 /* Book.swift in Sources */, + 53F5584D22316574004115F3 /* BookListTableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53F5583E22315783004115F3 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F5583F22315783004115F3 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53F5584322315784004115F3 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F5584422315784004115F3 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53F5584722315784004115F3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53F5584822315784004115F3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53F5584A22315784004115F3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicContainer/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicContainer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53F5584B22315784004115F3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicContainer/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicContainer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53F5583222315783004115F3 /* Build configuration list for PBXProject "DynamicContainer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F5584722315784004115F3 /* Debug */, + 53F5584822315784004115F3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53F5584922315784004115F3 /* Build configuration list for PBXNativeTarget "DynamicContainer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F5584A22315784004115F3 /* Debug */, + 53F5584B22315784004115F3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53F5582F22315783004115F3 /* Project object */; +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/AppDelegate.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/AppDelegate.swift new file mode 100644 index 0000000..ed2c55b --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/AppDelegate.swift @@ -0,0 +1,34 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/Contents.json b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/LaunchScreen.storyboard b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/Main.storyboard b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/Main.storyboard new file mode 100644 index 0000000..15fb128 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Base.lproj/Main.storyboard @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Book.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Book.swift new file mode 100644 index 0000000..0a01297 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Book.swift @@ -0,0 +1,35 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +struct Book { + let title: String + let author: String + let firstLine: String +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/BookListTableViewController.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/BookListTableViewController.swift new file mode 100644 index 0000000..d69493d --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/BookListTableViewController.swift @@ -0,0 +1,59 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol BookListDelegate: AnyObject { + func didSelect(index: Int) +} + +final class BookListTableViewController: UITableViewController { + + var list: [Book] = [] { + didSet { + tableView.reloadData() + } + } + + weak var delegate: BookListDelegate? + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Subtitle", for: indexPath) + cell.textLabel?.text = list[indexPath.row].title + cell.detailTextLabel?.text = list[indexPath.row].author + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + delegate?.didSelect(index: indexPath.row) + } +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/Info.plist b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/LibraryContainerViewController.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/LibraryContainerViewController.swift new file mode 100644 index 0000000..7ce2804 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/LibraryContainerViewController.swift @@ -0,0 +1,84 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LibraryContainerViewController: UIViewController { + + private let library = [ + Book(title: "Alice's Adventures in Wonderland", author: "Lewis Caroll", firstLine: "Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, ‘and what is the use of a book,’ thought Alice ‘without pictures or conversations?’"), + Book(title: "Emma", author: "Jane Austen", firstLine: "Emma Woodhouse, handsome, clever, and rich, with a comfortable home and happy disposition, seemed to unite some of the best blessings of existence; and had lived nearly twenty-one years in the world with very little to distress or vex her."), + Book(title: "Great Expectations", author: "Charles Dickens", firstLine: "My father's family name being Pirrip, and my Christian name Philip, my infant tongue could make of both names nothing longer or more explicit than Pip."), + Book(title: "Metamorphosis", author: "Franz Kafka", firstLine: "One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin."), + Book(title: "Peter Pan", author: "James M. Barrie", firstLine: "All children, except one, grow up.") + ] + + @IBOutlet private var messageHeightConstraint: NSLayoutConstraint? + + private var previewController: MessageViewController? + private var listTableViewController: BookListTableViewController? + + override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) { + super.preferredContentSizeDidChange(forChildContentContainer: container) + if (container as? MessageViewController) != nil { + messageHeightConstraint?.constant = container.preferredContentSize.height + } + } +} + +extension LibraryContainerViewController: SegueHandler { + + enum SegueIdentifier: String { + case embedList + case embedPreview + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + switch segueIdentifier(for: segue) { + case .embedList: + guard let childController = segue.destination as? BookListTableViewController else { + fatalError("Missing ListTableViewController") + } + listTableViewController = childController + listTableViewController?.list = library + listTableViewController?.delegate = self + case .embedPreview: + guard let childController = segue.destination as? MessageViewController else { + fatalError("Missing MessageViewController") + } + previewController = childController + previewController?.message = "Choose a book..." + } + } +} + +extension LibraryContainerViewController: BookListDelegate { + func didSelect(index: Int) { + previewController?.message = library[index].firstLine + } +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/MessageViewController.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/MessageViewController.swift new file mode 100644 index 0000000..fc1ac10 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/MessageViewController.swift @@ -0,0 +1,60 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class MessageViewController: UIViewController { + + @IBOutlet private var contentView: UIView! + @IBOutlet private var messageLabel: UILabel! + + var message: String? { + didSet { + updateMessage() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + updateMessage() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + calculatePreferredSize() + } + + private func calculatePreferredSize() { + let targetSize = CGSize(width: view.bounds.width, height: UIView.layoutFittingCompressedSize.height) + preferredContentSize = contentView.systemLayoutSizeFitting(targetSize) + } + + private func updateMessage() { + messageLabel?.text = message + } +} diff --git a/DynamicContainer/DynamicContainer-v1/DynamicContainer/SegueHandler.swift b/DynamicContainer/DynamicContainer-v1/DynamicContainer/SegueHandler.swift new file mode 100644 index 0000000..bb2be2b --- /dev/null +++ b/DynamicContainer/DynamicContainer-v1/DynamicContainer/SegueHandler.swift @@ -0,0 +1,48 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol SegueHandler { + associatedtype SegueIdentifier: RawRepresentable +} + +extension SegueHandler where Self: UIViewController, SegueIdentifier.RawValue == String { + + func performSegue(withIdentifier segueIdentifier: SegueIdentifier, sender: AnyObject?) { + performSegue(withIdentifier: segueIdentifier.rawValue, sender:sender) + } + + func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier { + guard let identifier = segue.identifier, + let segueIdentifier = SegueIdentifier(rawValue: identifier) else { + fatalError("Unknown Segue Identifier") + } + return segueIdentifier + } +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer.xcodeproj/project.pbxproj b/DynamicContainer/DynamicContainer-v2/DynamicContainer.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a0a3c72 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer.xcodeproj/project.pbxproj @@ -0,0 +1,357 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 53F5583B22315783004115F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5583A22315783004115F3 /* AppDelegate.swift */; }; + 53F5584022315783004115F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F5583E22315783004115F3 /* Main.storyboard */; }; + 53F5584222315784004115F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53F5584122315784004115F3 /* Assets.xcassets */; }; + 53F5584522315784004115F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F5584322315784004115F3 /* LaunchScreen.storyboard */; }; + 53F5584D22316574004115F3 /* BookListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5584C22316574004115F3 /* BookListTableViewController.swift */; }; + 53F5584F2231669B004115F3 /* LibraryContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */; }; + 53F5585122316C99004115F3 /* MessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585022316C99004115F3 /* MessageViewController.swift */; }; + 53F5585322316D55004115F3 /* Book.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585222316D55004115F3 /* Book.swift */; }; + 53F5585522316DBB004115F3 /* SegueHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F5585422316DBB004115F3 /* SegueHandler.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53F5583722315783004115F3 /* DynamicContainer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicContainer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53F5583A22315783004115F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53F5583F22315783004115F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53F5584122315784004115F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53F5584422315784004115F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53F5584622315784004115F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53F5584C22316574004115F3 /* BookListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookListTableViewController.swift; sourceTree = ""; }; + 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryContainerViewController.swift; sourceTree = ""; }; + 53F5585022316C99004115F3 /* MessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewController.swift; sourceTree = ""; }; + 53F5585222316D55004115F3 /* Book.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Book.swift; sourceTree = ""; }; + 53F5585422316DBB004115F3 /* SegueHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegueHandler.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53F5583422315783004115F3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53F5582E22315783004115F3 = { + isa = PBXGroup; + children = ( + 53F5583922315783004115F3 /* DynamicContainer */, + 53F5583822315783004115F3 /* Products */, + ); + sourceTree = ""; + }; + 53F5583822315783004115F3 /* Products */ = { + isa = PBXGroup; + children = ( + 53F5583722315783004115F3 /* DynamicContainer.app */, + ); + name = Products; + sourceTree = ""; + }; + 53F5583922315783004115F3 /* DynamicContainer */ = { + isa = PBXGroup; + children = ( + 53F5583A22315783004115F3 /* AppDelegate.swift */, + 53F5584E2231669B004115F3 /* LibraryContainerViewController.swift */, + 53F5584C22316574004115F3 /* BookListTableViewController.swift */, + 53F5585022316C99004115F3 /* MessageViewController.swift */, + 53F5585422316DBB004115F3 /* SegueHandler.swift */, + 53F5585222316D55004115F3 /* Book.swift */, + 53F5583E22315783004115F3 /* Main.storyboard */, + 53F5584122315784004115F3 /* Assets.xcassets */, + 53F5584322315784004115F3 /* LaunchScreen.storyboard */, + 53F5584622315784004115F3 /* Info.plist */, + ); + path = DynamicContainer; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53F5583622315783004115F3 /* DynamicContainer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53F5584922315784004115F3 /* Build configuration list for PBXNativeTarget "DynamicContainer" */; + buildPhases = ( + 53F5583322315783004115F3 /* Sources */, + 53F5583422315783004115F3 /* Frameworks */, + 53F5583522315783004115F3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DynamicContainer; + productName = DynamicContainer; + productReference = 53F5583722315783004115F3 /* DynamicContainer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53F5582F22315783004115F3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1020; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53F5583622315783004115F3 = { + CreatedOnToolsVersion = 10.2; + }; + }; + }; + buildConfigurationList = 53F5583222315783004115F3 /* Build configuration list for PBXProject "DynamicContainer" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53F5582E22315783004115F3; + productRefGroup = 53F5583822315783004115F3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53F5583622315783004115F3 /* DynamicContainer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53F5583522315783004115F3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F5584522315784004115F3 /* LaunchScreen.storyboard in Resources */, + 53F5584222315784004115F3 /* Assets.xcassets in Resources */, + 53F5584022315783004115F3 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53F5583322315783004115F3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F5585522316DBB004115F3 /* SegueHandler.swift in Sources */, + 53F5584F2231669B004115F3 /* LibraryContainerViewController.swift in Sources */, + 53F5583B22315783004115F3 /* AppDelegate.swift in Sources */, + 53F5585122316C99004115F3 /* MessageViewController.swift in Sources */, + 53F5585322316D55004115F3 /* Book.swift in Sources */, + 53F5584D22316574004115F3 /* BookListTableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53F5583E22315783004115F3 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F5583F22315783004115F3 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53F5584322315784004115F3 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F5584422315784004115F3 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53F5584722315784004115F3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53F5584822315784004115F3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53F5584A22315784004115F3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicContainer/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicContainer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53F5584B22315784004115F3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicContainer/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicContainer; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53F5583222315783004115F3 /* Build configuration list for PBXProject "DynamicContainer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F5584722315784004115F3 /* Debug */, + 53F5584822315784004115F3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53F5584922315784004115F3 /* Build configuration list for PBXNativeTarget "DynamicContainer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F5584A22315784004115F3 /* Debug */, + 53F5584B22315784004115F3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53F5582F22315783004115F3 /* Project object */; +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/AppDelegate.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/AppDelegate.swift new file mode 100644 index 0000000..ed2c55b --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/AppDelegate.swift @@ -0,0 +1,34 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/Contents.json b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/LaunchScreen.storyboard b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/Main.storyboard b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/Main.storyboard new file mode 100644 index 0000000..a06232e --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Base.lproj/Main.storyboard @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Book.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Book.swift new file mode 100644 index 0000000..0a01297 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Book.swift @@ -0,0 +1,35 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +struct Book { + let title: String + let author: String + let firstLine: String +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/BookListTableViewController.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/BookListTableViewController.swift new file mode 100644 index 0000000..d69493d --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/BookListTableViewController.swift @@ -0,0 +1,59 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol BookListDelegate: AnyObject { + func didSelect(index: Int) +} + +final class BookListTableViewController: UITableViewController { + + var list: [Book] = [] { + didSet { + tableView.reloadData() + } + } + + weak var delegate: BookListDelegate? + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Subtitle", for: indexPath) + cell.textLabel?.text = list[indexPath.row].title + cell.detailTextLabel?.text = list[indexPath.row].author + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + delegate?.didSelect(index: indexPath.row) + } +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/Info.plist b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/LibraryContainerViewController.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/LibraryContainerViewController.swift new file mode 100644 index 0000000..8f30cb1 --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/LibraryContainerViewController.swift @@ -0,0 +1,76 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class LibraryContainerViewController: UIViewController { + + private let library = [ + Book(title: "Alice's Adventures in Wonderland", author: "Lewis Caroll", firstLine: "Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, ‘and what is the use of a book,’ thought Alice ‘without pictures or conversations?’"), + Book(title: "Emma", author: "Jane Austen", firstLine: "Emma Woodhouse, handsome, clever, and rich, with a comfortable home and happy disposition, seemed to unite some of the best blessings of existence; and had lived nearly twenty-one years in the world with very little to distress or vex her."), + Book(title: "Great Expectations", author: "Charles Dickens", firstLine: "My father's family name being Pirrip, and my Christian name Philip, my infant tongue could make of both names nothing longer or more explicit than Pip."), + Book(title: "Metamorphosis", author: "Franz Kafka", firstLine: "One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin."), + Book(title: "Peter Pan", author: "James M. Barrie", firstLine: "All children, except one, grow up.") + ] + + private var previewController: MessageViewController? + private var listTableViewController: BookListTableViewController? +} + +extension LibraryContainerViewController: SegueHandler { + + enum SegueIdentifier: String { + case embedList + case embedPreview + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + switch segueIdentifier(for: segue) { + case .embedList: + guard let childController = segue.destination as? BookListTableViewController else { + fatalError("Missing ListTableViewController") + } + listTableViewController = childController + listTableViewController?.list = library + listTableViewController?.delegate = self + case .embedPreview: + guard let childController = segue.destination as? MessageViewController else { + fatalError("Missing MessageViewController") + } + previewController = childController + previewController?.message = "Choose a book..." + previewController?.view.translatesAutoresizingMaskIntoConstraints = false + } + } +} + +extension LibraryContainerViewController: BookListDelegate { + func didSelect(index: Int) { + previewController?.message = library[index].firstLine + } +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/MessageViewController.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/MessageViewController.swift new file mode 100644 index 0000000..4301e5e --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/MessageViewController.swift @@ -0,0 +1,50 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class MessageViewController: UIViewController { + + @IBOutlet private var contentView: UIView! + @IBOutlet private var messageLabel: UILabel! + + var message: String? { + didSet { + updateMessage() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + updateMessage() + } + + private func updateMessage() { + messageLabel?.text = message + } +} diff --git a/DynamicContainer/DynamicContainer-v2/DynamicContainer/SegueHandler.swift b/DynamicContainer/DynamicContainer-v2/DynamicContainer/SegueHandler.swift new file mode 100644 index 0000000..bb2be2b --- /dev/null +++ b/DynamicContainer/DynamicContainer-v2/DynamicContainer/SegueHandler.swift @@ -0,0 +1,48 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol SegueHandler { + associatedtype SegueIdentifier: RawRepresentable +} + +extension SegueHandler where Self: UIViewController, SegueIdentifier.RawValue == String { + + func performSegue(withIdentifier segueIdentifier: SegueIdentifier, sender: AnyObject?) { + performSegue(withIdentifier: segueIdentifier.rawValue, sender:sender) + } + + func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier { + guard let identifier = segue.identifier, + let segueIdentifier = SegueIdentifier(rawValue: identifier) else { + fatalError("Unknown Segue Identifier") + } + return segueIdentifier + } +} diff --git a/DynamicContainer/README.md b/DynamicContainer/README.md new file mode 100644 index 0000000..9ce1e8b --- /dev/null +++ b/DynamicContainer/README.md @@ -0,0 +1,9 @@ +# Self-sizing Child Views + +This project is an example of using the `UIContentContainer` protocol to allow a child view controller to tell its parent its preferred content size. + +See the following blog post for more details: + +[Self-sizing Child Views](https://useyourloaf.com/blog/self-sizing-child-views/) + +See the second example in the folder `DynamicContainer-v2` for an example of how to achieve the same effect without using the preferred content size. diff --git a/DynamicText/DynamicText.xcodeproj/project.pbxproj b/DynamicText/DynamicText.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8707dce --- /dev/null +++ b/DynamicText/DynamicText.xcodeproj/project.pbxproj @@ -0,0 +1,383 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 531B320A1861EFB6005F2332 /* UYLScaledTextStyleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 531B32091861EFB6005F2332 /* UYLScaledTextStyleViewController.m */; }; + 53615D2F1F41B67900C7D904 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53615D2D1F41B67900C7D904 /* LaunchScreen.storyboard */; }; + 5393B52E17F83CB600AD2292 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5393B52D17F83CB600AD2292 /* Foundation.framework */; }; + 5393B53017F83CB600AD2292 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5393B52F17F83CB600AD2292 /* CoreGraphics.framework */; }; + 5393B53217F83CB600AD2292 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5393B53117F83CB600AD2292 /* UIKit.framework */; }; + 5393B53817F83CB600AD2292 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5393B53617F83CB600AD2292 /* InfoPlist.strings */; }; + 5393B53A17F83CB600AD2292 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5393B53917F83CB600AD2292 /* main.m */; }; + 5393B53E17F83CB600AD2292 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5393B53D17F83CB600AD2292 /* UYLAppDelegate.m */; }; + 5393B54117F83CB600AD2292 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5393B53F17F83CB600AD2292 /* Main.storyboard */; }; + 5393B54617F83CB600AD2292 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5393B54517F83CB600AD2292 /* Images.xcassets */; }; + 5393B56417F83DB000AD2292 /* UYLTextStyleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5393B56317F83DB000AD2292 /* UYLTextStyleViewController.m */; }; + 53FE524C1871CDB700DE5F24 /* UIFont+UYLScaledFont.m in Sources */ = {isa = PBXBuildFile; fileRef = 53FE524B1871CDB700DE5F24 /* UIFont+UYLScaledFont.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 531B32081861EFB6005F2332 /* UYLScaledTextStyleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLScaledTextStyleViewController.h; sourceTree = ""; }; + 531B32091861EFB6005F2332 /* UYLScaledTextStyleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLScaledTextStyleViewController.m; sourceTree = ""; }; + 5325F8AD18020B0B0000A32A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53615D2E1F41B67900C7D904 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5393B52A17F83CB600AD2292 /* DynamicText.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicText.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5393B52D17F83CB600AD2292 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5393B52F17F83CB600AD2292 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5393B53117F83CB600AD2292 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5393B53517F83CB600AD2292 /* DynamicText-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DynamicText-Info.plist"; sourceTree = ""; }; + 5393B53717F83CB600AD2292 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5393B53917F83CB600AD2292 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5393B53B17F83CB600AD2292 /* DynamicText-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DynamicText-Prefix.pch"; sourceTree = ""; }; + 5393B53C17F83CB600AD2292 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 5393B53D17F83CB600AD2292 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 5393B54017F83CB600AD2292 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5393B54517F83CB600AD2292 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5393B54C17F83CB600AD2292 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 5393B56217F83DB000AD2292 /* UYLTextStyleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTextStyleViewController.h; sourceTree = ""; }; + 5393B56317F83DB000AD2292 /* UYLTextStyleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTextStyleViewController.m; sourceTree = ""; }; + 53FE524A1871CDB700DE5F24 /* UIFont+UYLScaledFont.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIFont+UYLScaledFont.h"; sourceTree = ""; }; + 53FE524B1871CDB700DE5F24 /* UIFont+UYLScaledFont.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+UYLScaledFont.m"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5393B52717F83CB600AD2292 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5393B53017F83CB600AD2292 /* CoreGraphics.framework in Frameworks */, + 5393B53217F83CB600AD2292 /* UIKit.framework in Frameworks */, + 5393B52E17F83CB600AD2292 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5393B52117F83CB600AD2292 = { + isa = PBXGroup; + children = ( + 5325F8AD18020B0B0000A32A /* README.md */, + 5393B53317F83CB600AD2292 /* DynamicText */, + 5393B52C17F83CB600AD2292 /* Frameworks */, + 5393B52B17F83CB600AD2292 /* Products */, + ); + sourceTree = ""; + }; + 5393B52B17F83CB600AD2292 /* Products */ = { + isa = PBXGroup; + children = ( + 5393B52A17F83CB600AD2292 /* DynamicText.app */, + ); + name = Products; + sourceTree = ""; + }; + 5393B52C17F83CB600AD2292 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5393B52D17F83CB600AD2292 /* Foundation.framework */, + 5393B52F17F83CB600AD2292 /* CoreGraphics.framework */, + 5393B53117F83CB600AD2292 /* UIKit.framework */, + 5393B54C17F83CB600AD2292 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5393B53317F83CB600AD2292 /* DynamicText */ = { + isa = PBXGroup; + children = ( + 5393B53C17F83CB600AD2292 /* UYLAppDelegate.h */, + 5393B53D17F83CB600AD2292 /* UYLAppDelegate.m */, + 5393B56217F83DB000AD2292 /* UYLTextStyleViewController.h */, + 5393B56317F83DB000AD2292 /* UYLTextStyleViewController.m */, + 531B32081861EFB6005F2332 /* UYLScaledTextStyleViewController.h */, + 531B32091861EFB6005F2332 /* UYLScaledTextStyleViewController.m */, + 53FE524A1871CDB700DE5F24 /* UIFont+UYLScaledFont.h */, + 53FE524B1871CDB700DE5F24 /* UIFont+UYLScaledFont.m */, + 5393B53F17F83CB600AD2292 /* Main.storyboard */, + 53615D2D1F41B67900C7D904 /* LaunchScreen.storyboard */, + 5393B54517F83CB600AD2292 /* Images.xcassets */, + 5393B53417F83CB600AD2292 /* Supporting Files */, + ); + path = DynamicText; + sourceTree = ""; + }; + 5393B53417F83CB600AD2292 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5393B53517F83CB600AD2292 /* DynamicText-Info.plist */, + 5393B53617F83CB600AD2292 /* InfoPlist.strings */, + 5393B53917F83CB600AD2292 /* main.m */, + 5393B53B17F83CB600AD2292 /* DynamicText-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5393B52917F83CB600AD2292 /* DynamicText */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5393B55C17F83CB600AD2292 /* Build configuration list for PBXNativeTarget "DynamicText" */; + buildPhases = ( + 5393B52617F83CB600AD2292 /* Sources */, + 5393B52717F83CB600AD2292 /* Frameworks */, + 5393B52817F83CB600AD2292 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DynamicText; + productName = DynamicText; + productReference = 5393B52A17F83CB600AD2292 /* DynamicText.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5393B52217F83CB600AD2292 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 5393B52517F83CB600AD2292 /* Build configuration list for PBXProject "DynamicText" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5393B52117F83CB600AD2292; + productRefGroup = 5393B52B17F83CB600AD2292 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5393B52917F83CB600AD2292 /* DynamicText */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5393B52817F83CB600AD2292 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5393B54617F83CB600AD2292 /* Images.xcassets in Resources */, + 53615D2F1F41B67900C7D904 /* LaunchScreen.storyboard in Resources */, + 5393B53817F83CB600AD2292 /* InfoPlist.strings in Resources */, + 5393B54117F83CB600AD2292 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5393B52617F83CB600AD2292 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5393B53A17F83CB600AD2292 /* main.m in Sources */, + 5393B56417F83DB000AD2292 /* UYLTextStyleViewController.m in Sources */, + 5393B53E17F83CB600AD2292 /* UYLAppDelegate.m in Sources */, + 53FE524C1871CDB700DE5F24 /* UIFont+UYLScaledFont.m in Sources */, + 531B320A1861EFB6005F2332 /* UYLScaledTextStyleViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53615D2D1F41B67900C7D904 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53615D2E1F41B67900C7D904 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 5393B53617F83CB600AD2292 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5393B53717F83CB600AD2292 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5393B53F17F83CB600AD2292 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5393B54017F83CB600AD2292 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5393B55A17F83CB600AD2292 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5393B55B17F83CB600AD2292 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5393B55D17F83CB600AD2292 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1.3; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "DynamicText/DynamicText-Prefix.pch"; + INFOPLIST_FILE = "DynamicText/DynamicText-Info.plist"; + MARKETING_VERSION = 1.3; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5393B55E17F83CB600AD2292 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1.3; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "DynamicText/DynamicText-Prefix.pch"; + INFOPLIST_FILE = "DynamicText/DynamicText-Info.plist"; + MARKETING_VERSION = 1.3; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5393B52517F83CB600AD2292 /* Build configuration list for PBXProject "DynamicText" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5393B55A17F83CB600AD2292 /* Debug */, + 5393B55B17F83CB600AD2292 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5393B55C17F83CB600AD2292 /* Build configuration list for PBXNativeTarget "DynamicText" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5393B55D17F83CB600AD2292 /* Debug */, + 5393B55E17F83CB600AD2292 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5393B52217F83CB600AD2292 /* Project object */; +} diff --git a/DynamicText/DynamicText/Base.lproj/LaunchScreen.storyboard b/DynamicText/DynamicText/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f746012 --- /dev/null +++ b/DynamicText/DynamicText/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicText/DynamicText/Base.lproj/Main.storyboard b/DynamicText/DynamicText/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f069627 --- /dev/null +++ b/DynamicText/DynamicText/Base.lproj/Main.storyboard @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicText/DynamicText/DynamicText-Info.plist b/DynamicText/DynamicText/DynamicText-Info.plist new file mode 100644 index 0000000..2348c0a --- /dev/null +++ b/DynamicText/DynamicText/DynamicText-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/DynamicText/DynamicText/DynamicText-Prefix.pch b/DynamicText/DynamicText/DynamicText-Prefix.pch new file mode 100644 index 0000000..82a2bb4 --- /dev/null +++ b/DynamicText/DynamicText/DynamicText-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/Contents.json b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1120389 --- /dev/null +++ b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-40.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-120.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-180.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-41.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-42.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-167.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-1024.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000..4a1a9de Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-120.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-120.png new file mode 100644 index 0000000..d4b42eb Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-120.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-167.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-167.png new file mode 100644 index 0000000..0a5ec66 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-167.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-180.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-180.png new file mode 100644 index 0000000..e943cc3 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-180.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-20.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-20.png new file mode 100644 index 0000000..3c16adf Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-20.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000..b918cea Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png new file mode 100644 index 0000000..3c599a5 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x-1.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@3x.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@3x.png new file mode 100644 index 0000000..f32646a Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-29@3x.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png new file mode 100644 index 0000000..afcf538 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x-1.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-41.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-41.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-41.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-42.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-42.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-42.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60.png new file mode 100644 index 0000000..fd2eff6 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60@2x.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 0000000..515d2b6 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-60@2x.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000..90d600a Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76@2x.png b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000..6b529b8 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Contents.json b/DynamicText/DynamicText/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/DynamicText/DynamicText/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/Contents.json b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/Contents.json new file mode 100644 index 0000000..f7afaee --- /dev/null +++ b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first30.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "first60.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "first90.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first30.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first30.png new file mode 100644 index 0000000..e7f0902 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first30.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first60.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first60.png new file mode 100644 index 0000000..975a75f Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first60.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first90.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first90.png new file mode 100644 index 0000000..92341c2 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/First.imageset/first90.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/Contents.json b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/Contents.json new file mode 100644 index 0000000..fd58914 --- /dev/null +++ b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second30.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "second60.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "second90.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second30.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second30.png new file mode 100644 index 0000000..728d7f6 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second30.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second60.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second60.png new file mode 100644 index 0000000..9cd7cb3 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second60.png differ diff --git a/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second90.png b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second90.png new file mode 100644 index 0000000..6170461 Binary files /dev/null and b/DynamicText/DynamicText/Images.xcassets/Tab Bar/Second.imageset/second90.png differ diff --git a/DynamicText/DynamicText/UIFont+UYLScaledFont.h b/DynamicText/DynamicText/UIFont+UYLScaledFont.h new file mode 100644 index 0000000..3dc52dd --- /dev/null +++ b/DynamicText/DynamicText/UIFont+UYLScaledFont.h @@ -0,0 +1,50 @@ +// +// UIFont+UYLScaledFont.h +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UIFont (UYLScaledFont) + +// +uylPreferredFontForTextStyle:scale: +// +// Return a UIFont object for the specified text style that is scaled by the +// speficied scale factor. +// +// The text style is a UIFontDescriptor Text Style +// +// The scaleFactor modifies the default point size of the text style. So for +// a font that is twice the default size specify a scaleFactor of 2.0. + ++ (UIFont *)uylPreferredFontForTextStyle:(NSString *)style scale:(CGFloat)scaleFactor; + +@end diff --git a/DynamicText/DynamicText/UIFont+UYLScaledFont.m b/DynamicText/DynamicText/UIFont+UYLScaledFont.m new file mode 100644 index 0000000..0efddd2 --- /dev/null +++ b/DynamicText/DynamicText/UIFont+UYLScaledFont.m @@ -0,0 +1,46 @@ +// +// UIFont+UYLScaledFont.m +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UIFont+UYLScaledFont.h" + +@implementation UIFont (UYLScaledFont) + ++ (UIFont *)uylPreferredFontForTextStyle:(NSString *)style scale:(CGFloat)scaleFactor +{ + UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:style]; + CGFloat pointSize = descriptor.pointSize * scaleFactor; + UIFont *font = [UIFont fontWithDescriptor:descriptor size:pointSize]; + return font; +} + +@end diff --git a/DynamicText/DynamicText/UYLAppDelegate.h b/DynamicText/DynamicText/UYLAppDelegate.h new file mode 100644 index 0000000..5efc6de --- /dev/null +++ b/DynamicText/DynamicText/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/DynamicText/DynamicText/UYLAppDelegate.m b/DynamicText/DynamicText/UYLAppDelegate.m new file mode 100644 index 0000000..59ba911 --- /dev/null +++ b/DynamicText/DynamicText/UYLAppDelegate.m @@ -0,0 +1,37 @@ +// +// UYLAppDelegate.m +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +@end \ No newline at end of file diff --git a/DynamicText/DynamicText/UYLScaledTextStyleViewController.h b/DynamicText/DynamicText/UYLScaledTextStyleViewController.h new file mode 100644 index 0000000..3c408b4 --- /dev/null +++ b/DynamicText/DynamicText/UYLScaledTextStyleViewController.h @@ -0,0 +1,13 @@ +// +// UYLScaledTextStyleViewController.h +// DynamicText +// +// Created by Keith Harrison on 18/12/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import "UYLTextStyleViewController.h" + +@interface UYLScaledTextStyleViewController : UYLTextStyleViewController + +@end diff --git a/DynamicText/DynamicText/UYLScaledTextStyleViewController.m b/DynamicText/DynamicText/UYLScaledTextStyleViewController.m new file mode 100644 index 0000000..5214e5e --- /dev/null +++ b/DynamicText/DynamicText/UYLScaledTextStyleViewController.m @@ -0,0 +1,30 @@ +// +// UYLScaledTextStyleViewController.m +// DynamicText +// +// Created by Keith Harrison on 18/12/2013. +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// + +#import "UYLScaledTextStyleViewController.h" +#import "UIFont+UYLScaledFont.h" + +@implementation UYLScaledTextStyleViewController + +#pragma mark - +#pragma mark === View Life Cycle === +#pragma mark - + +- (void)configureView +{ + CGFloat scaleFactor = 2.0; + self.textSizeLabel.text = [[UIApplication sharedApplication] preferredContentSizeCategory]; + self.headlineLabel.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleHeadline scale:scaleFactor]; + self.subheadLabel.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleSubheadline scale:scaleFactor]; + self.bodyLabel.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleBody scale:scaleFactor]; + self.caption1Label.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleCaption1 scale:scaleFactor]; + self.caption2Label.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleCaption2 scale:scaleFactor]; + self.footnoteLabel.font = [UIFont uylPreferredFontForTextStyle:UIFontTextStyleFootnote scale:scaleFactor]; +} + +@end diff --git a/DynamicText/DynamicText/UYLTextStyleViewController.h b/DynamicText/DynamicText/UYLTextStyleViewController.h new file mode 100644 index 0000000..88bbcef --- /dev/null +++ b/DynamicText/DynamicText/UYLTextStyleViewController.h @@ -0,0 +1,46 @@ +// +// UYLTableViewController.h +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTextStyleViewController : UIViewController + +@property (weak, nonatomic) IBOutlet UILabel *textSizeLabel; +@property (weak, nonatomic) IBOutlet UILabel *headlineLabel; +@property (weak, nonatomic) IBOutlet UILabel *subheadLabel; +@property (weak, nonatomic) IBOutlet UILabel *bodyLabel; +@property (weak, nonatomic) IBOutlet UILabel *caption1Label; +@property (weak, nonatomic) IBOutlet UILabel *caption2Label; +@property (weak, nonatomic) IBOutlet UILabel *footnoteLabel; + +@end diff --git a/DynamicText/DynamicText/UYLTextStyleViewController.m b/DynamicText/DynamicText/UYLTextStyleViewController.m new file mode 100644 index 0000000..6871248 --- /dev/null +++ b/DynamicText/DynamicText/UYLTextStyleViewController.m @@ -0,0 +1,77 @@ +// +// UYLTableViewController.m +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLTextStyleViewController.h" + +@implementation UYLTextStyleViewController + +#pragma mark - +#pragma mark === View Life Cycle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification + object:nil]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [self configureView]; +} + +- (void)configureView +{ + self.textSizeLabel.text = [[UIApplication sharedApplication] preferredContentSizeCategory]; + self.headlineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + self.subheadLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; + self.bodyLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + self.caption1Label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; + self.caption2Label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; + self.footnoteLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; +} + +#pragma mark - +#pragma mark === Notification Methods === +#pragma mark - + +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self configureView]; +} + +@end diff --git a/DynamicText/DynamicText/en.lproj/InfoPlist.strings b/DynamicText/DynamicText/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/DynamicText/DynamicText/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/DynamicText/DynamicText/main.m b/DynamicText/DynamicText/main.m new file mode 100644 index 0000000..94553a1 --- /dev/null +++ b/DynamicText/DynamicText/main.m @@ -0,0 +1,43 @@ +// +// main.m +// DynamicText +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/DynamicText/README.md b/DynamicText/README.md new file mode 100644 index 0000000..14c9d11 --- /dev/null +++ b/DynamicText/README.md @@ -0,0 +1,32 @@ +# DynamicText + +## Responding to text size changes + +This is a example project showing how to respond to the user changing +the preferred text size. + +**Minimum deployment target is now iOS 9.0 using Xcode 11** + +The `UYLTextStyleViewController` shows the standard way to listen for +and respond to changes to the users preferred text size using the +built-in `UIFont` Text Styles. + +For further details see the following blog post: + ++ [Supporting Dynamic Type](https://useyourloaf.com/blog/supporting-dynamic-type/) + +The `UYLScaledTextStyleViewController` extends the basic approach by +showing how to scale the preferred fonts using a `UIFontDescriptor`. +A convenience method to return the scaled font is added as a +category of `UIFont` for this purpose. + +For further details see the following blog post: + ++ [Scaling Synamic Type With Font Descriptors](https://useyourloaf.com/blog/scaling-dynamic-type-with-font-descriptors/) + +## History + +Version 1.3 11 January 2020 Updated for Xcode 11 +Version 1.2 14 August 2017 Updated for Xcode 8 and iOS 10 +Version 1.1 30 December 2013 Added UYLScaledTextViewController +Version 1.0 06 October 2013 Initial version. diff --git a/DynamicWebKit/DynamicWebKit.xcodeproj/project.pbxproj b/DynamicWebKit/DynamicWebKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000..995fc45 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit.xcodeproj/project.pbxproj @@ -0,0 +1,366 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 53A2B53B1F94DBE500095FAD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A2B53A1F94DBE500095FAD /* AppDelegate.swift */; }; + 53A2B53D1F94DBE500095FAD /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A2B53C1F94DBE500095FAD /* WebViewController.swift */; }; + 53A2B5401F94DBE500095FAD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53A2B53E1F94DBE500095FAD /* Main.storyboard */; }; + 53A2B5421F94DBE500095FAD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53A2B5411F94DBE500095FAD /* Assets.xcassets */; }; + 53A2B5451F94DBE500095FAD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53A2B5431F94DBE500095FAD /* LaunchScreen.storyboard */; }; + 53A2B54D1F94DC9700095FAD /* default.html in Resources */ = {isa = PBXBuildFile; fileRef = 53A2B54C1F94DC9700095FAD /* default.html */; }; + 53A2B54F1F94DD8200095FAD /* stylesheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 53A2B54E1F94DD8200095FAD /* stylesheet.css */; }; + 53E34E032403D85700EE575E /* 001-dark.png in Resources */ = {isa = PBXBuildFile; fileRef = 53E34E022403D67600EE575E /* 001-dark.png */; }; + 53E34E042403D85A00EE575E /* 001-dark@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53E34DFF2403D67600EE575E /* 001-dark@2x.png */; }; + 53E34E052403D85E00EE575E /* 001.png in Resources */ = {isa = PBXBuildFile; fileRef = 53E34E012403D67600EE575E /* 001.png */; }; + 53E34E062403D86100EE575E /* 001@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53E34E002403D67600EE575E /* 001@2x.png */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53A2B5371F94DBE500095FAD /* DynamicWebKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicWebKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53A2B53A1F94DBE500095FAD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53A2B53C1F94DBE500095FAD /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; + 53A2B53F1F94DBE500095FAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53A2B5411F94DBE500095FAD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53A2B5441F94DBE500095FAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53A2B5461F94DBE500095FAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53A2B54C1F94DC9700095FAD /* default.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = default.html; sourceTree = ""; }; + 53A2B54E1F94DD8200095FAD /* stylesheet.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = stylesheet.css; sourceTree = ""; }; + 53A2B5501F94F14800095FAD /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53E34DFF2403D67600EE575E /* 001-dark@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "001-dark@2x.png"; sourceTree = ""; }; + 53E34E002403D67600EE575E /* 001@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "001@2x.png"; sourceTree = ""; }; + 53E34E012403D67600EE575E /* 001.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 001.png; sourceTree = ""; }; + 53E34E022403D67600EE575E /* 001-dark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "001-dark.png"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53A2B5341F94DBE500095FAD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53A2B52E1F94DBE500095FAD = { + isa = PBXGroup; + children = ( + 53A2B5501F94F14800095FAD /* README.md */, + 53A2B5391F94DBE500095FAD /* DynamicWebKit */, + 53A2B5381F94DBE500095FAD /* Products */, + ); + sourceTree = ""; + }; + 53A2B5381F94DBE500095FAD /* Products */ = { + isa = PBXGroup; + children = ( + 53A2B5371F94DBE500095FAD /* DynamicWebKit.app */, + ); + name = Products; + sourceTree = ""; + }; + 53A2B5391F94DBE500095FAD /* DynamicWebKit */ = { + isa = PBXGroup; + children = ( + 53A2B53A1F94DBE500095FAD /* AppDelegate.swift */, + 53A2B53C1F94DBE500095FAD /* WebViewController.swift */, + 53E34DFE2403D58400EE575E /* HTML */, + 53A2B53E1F94DBE500095FAD /* Main.storyboard */, + 53A2B5411F94DBE500095FAD /* Assets.xcassets */, + 53A2B5431F94DBE500095FAD /* LaunchScreen.storyboard */, + 53A2B5461F94DBE500095FAD /* Info.plist */, + ); + path = DynamicWebKit; + sourceTree = ""; + }; + 53E34DFE2403D58400EE575E /* HTML */ = { + isa = PBXGroup; + children = ( + 53A2B54C1F94DC9700095FAD /* default.html */, + 53E34E022403D67600EE575E /* 001-dark.png */, + 53E34DFF2403D67600EE575E /* 001-dark@2x.png */, + 53E34E012403D67600EE575E /* 001.png */, + 53E34E002403D67600EE575E /* 001@2x.png */, + 53A2B54E1F94DD8200095FAD /* stylesheet.css */, + ); + path = HTML; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53A2B5361F94DBE500095FAD /* DynamicWebKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53A2B5491F94DBE500095FAD /* Build configuration list for PBXNativeTarget "DynamicWebKit" */; + buildPhases = ( + 53A2B5331F94DBE500095FAD /* Sources */, + 53A2B5341F94DBE500095FAD /* Frameworks */, + 53A2B5351F94DBE500095FAD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DynamicWebKit; + productName = DynamicWebKit; + productReference = 53A2B5371F94DBE500095FAD /* DynamicWebKit.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53A2B52F1F94DBE500095FAD /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53A2B5361F94DBE500095FAD = { + CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53A2B5321F94DBE500095FAD /* Build configuration list for PBXProject "DynamicWebKit" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53A2B52E1F94DBE500095FAD; + productRefGroup = 53A2B5381F94DBE500095FAD /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53A2B5361F94DBE500095FAD /* DynamicWebKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53A2B5351F94DBE500095FAD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E34E042403D85A00EE575E /* 001-dark@2x.png in Resources */, + 53A2B54D1F94DC9700095FAD /* default.html in Resources */, + 53A2B54F1F94DD8200095FAD /* stylesheet.css in Resources */, + 53E34E052403D85E00EE575E /* 001.png in Resources */, + 53A2B5451F94DBE500095FAD /* LaunchScreen.storyboard in Resources */, + 53E34E032403D85700EE575E /* 001-dark.png in Resources */, + 53A2B5421F94DBE500095FAD /* Assets.xcassets in Resources */, + 53E34E062403D86100EE575E /* 001@2x.png in Resources */, + 53A2B5401F94DBE500095FAD /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53A2B5331F94DBE500095FAD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53A2B53D1F94DBE500095FAD /* WebViewController.swift in Sources */, + 53A2B53B1F94DBE500095FAD /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53A2B53E1F94DBE500095FAD /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53A2B53F1F94DBE500095FAD /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53A2B5431F94DBE500095FAD /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53A2B5441F94DBE500095FAD /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53A2B5471F94DBE500095FAD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53A2B5481F94DBE500095FAD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53A2B54A1F94DBE500095FAD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicWebKit/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicWebKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53A2B54B1F94DBE500095FAD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = DynamicWebKit/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.DynamicWebKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53A2B5321F94DBE500095FAD /* Build configuration list for PBXProject "DynamicWebKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53A2B5471F94DBE500095FAD /* Debug */, + 53A2B5481F94DBE500095FAD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53A2B5491F94DBE500095FAD /* Build configuration list for PBXNativeTarget "DynamicWebKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53A2B54A1F94DBE500095FAD /* Debug */, + 53A2B54B1F94DBE500095FAD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53A2B52F1F94DBE500095FAD /* Project object */; +} diff --git a/DynamicWebKit/DynamicWebKit/AppDelegate.swift b/DynamicWebKit/DynamicWebKit/AppDelegate.swift new file mode 100644 index 0000000..6420758 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/AppDelegate.swift @@ -0,0 +1,35 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/DynamicWebKit/DynamicWebKit/Assets.xcassets/AppIcon.appiconset/Contents.json b/DynamicWebKit/DynamicWebKit/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DynamicWebKit/DynamicWebKit/Base.lproj/LaunchScreen.storyboard b/DynamicWebKit/DynamicWebKit/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f83f6fd --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicWebKit/DynamicWebKit/Base.lproj/Main.storyboard b/DynamicWebKit/DynamicWebKit/Base.lproj/Main.storyboard new file mode 100644 index 0000000..c0a6762 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/Base.lproj/Main.storyboard @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DynamicWebKit/DynamicWebKit/HTML/001-dark.png b/DynamicWebKit/DynamicWebKit/HTML/001-dark.png new file mode 100644 index 0000000..98e7b46 Binary files /dev/null and b/DynamicWebKit/DynamicWebKit/HTML/001-dark.png differ diff --git a/DynamicWebKit/DynamicWebKit/HTML/001-dark@2x.png b/DynamicWebKit/DynamicWebKit/HTML/001-dark@2x.png new file mode 100644 index 0000000..867a616 Binary files /dev/null and b/DynamicWebKit/DynamicWebKit/HTML/001-dark@2x.png differ diff --git a/DynamicWebKit/DynamicWebKit/HTML/001.png b/DynamicWebKit/DynamicWebKit/HTML/001.png new file mode 100644 index 0000000..1d96a9a Binary files /dev/null and b/DynamicWebKit/DynamicWebKit/HTML/001.png differ diff --git a/DynamicWebKit/DynamicWebKit/HTML/001@2x.png b/DynamicWebKit/DynamicWebKit/HTML/001@2x.png new file mode 100644 index 0000000..15688c5 Binary files /dev/null and b/DynamicWebKit/DynamicWebKit/HTML/001@2x.png differ diff --git a/DynamicWebKit/DynamicWebKit/HTML/default.html b/DynamicWebKit/DynamicWebKit/HTML/default.html new file mode 100644 index 0000000..96c14f7 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/HTML/default.html @@ -0,0 +1,21 @@ + + + + + + +User Guide + + +

Dynamic Type With WebKit

+

Getting Started

+

An example of using dynamic type fonts with HTML content displayed in a WKWebView. Changing the text size in Settings should also change the text in this web view.

+

Handling Images

+

An example of an image with a dark mode variation

+ + +Xcode source editor + + + + diff --git a/DynamicWebKit/DynamicWebKit/HTML/stylesheet.css b/DynamicWebKit/DynamicWebKit/HTML/stylesheet.css new file mode 100644 index 0000000..00998a7 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/HTML/stylesheet.css @@ -0,0 +1,40 @@ +:root { + color-scheme: light dark; + --title-color: red; + --subhead-color: green; + --link-color: blue; +} + +@media screen and (prefers-color-scheme: dark) { + :root { + --title-color: #ff8080; + --subhead-color: #80ff80; + --link-color: #93d5ff; + } +} + +body { + font: -apple-system-body; +} + +h1 { + font: -apple-system-headline; + color: var(--title-color); +} + +h2 { + font: -apple-system-subheadline; + color: var(--subhead-color); +} + +footer { + font: -apple-system-footnote; +} + +a { + color: var(--link-color); +} + +img { + max-width: 100%; +} diff --git a/DynamicWebKit/DynamicWebKit/Info.plist b/DynamicWebKit/DynamicWebKit/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/DynamicWebKit/DynamicWebKit/WebViewController.swift b/DynamicWebKit/DynamicWebKit/WebViewController.swift new file mode 100644 index 0000000..90b5382 --- /dev/null +++ b/DynamicWebKit/DynamicWebKit/WebViewController.swift @@ -0,0 +1,63 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017-2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit +import WebKit + +final class WebViewController: UIViewController { + var html: String = "default" { + didSet { + loadHTML(html) + } + } + + private lazy var webView: WKWebView = { + let preferences = WKPreferences() + preferences.javaScriptEnabled = false + let configuration = WKWebViewConfiguration() + configuration.preferences = preferences + return WKWebView(frame: .zero, configuration: configuration) + }() + + override func loadView() { + view = webView + loadHTML(html) + NotificationCenter.default.addObserver(self, selector: #selector(contentSizeDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) + } + + @objc private func contentSizeDidChange(_ notification: Notification) { + webView.reload() + } + + private func loadHTML(_ name: String) { + if let url = Bundle.main.url(forResource: name, withExtension: "html") { + webView.loadFileURL(url, allowingReadAccessTo: url) + } + } +} diff --git a/DynamicWebKit/README.md b/DynamicWebKit/README.md new file mode 100644 index 0000000..3f59978 --- /dev/null +++ b/DynamicWebKit/README.md @@ -0,0 +1,14 @@ +# Using Dynamic Type With Web Views + +An example of how to use the Apple system fonts in a CSS stylesheet so static HTML content in a web view respects the user's choice of content size. + +## Adding Support For Dark Mode + +I've updated this project to support dark mode (requires iOS 13). + +## Further Details + +For further details see the following blog posts: + ++ [Using Dynamic Type With Web Views](https://useyourloaf.com/blog/using-dynamic-type-with-web-views/) ++ [Supporting Dark Mode In WkWebView](https://useyourloaf.com/blog/supporting-dark-mode-in-wkwebview/) diff --git a/Encode/README.md b/Encode/README.md new file mode 100644 index 0000000..4b9a51e --- /dev/null +++ b/Encode/README.md @@ -0,0 +1,44 @@ +--- +Encode - experimenting with different URL encoding schemes + +Version 1.0 01 Jan 2016 Initial version. + +--- + +A String extension that provides two different approaches to +percent encode a URL query. + +### public func stringByAddingPercentEncodingForRFC3986() -> String? + +Returns a new string made from the receiver by replacing characters which are +reserved in a URI query with percent encoded characters. + +The following characters are not considered reserved in a URI query +by RFC 3986: + +- Alpha "a...z" "A...Z" +- Numberic "0...9" +- Unreserved "-._~" + +In addition the reserved characters "/" and "?" have no reserved purpose in the +query component of a URI so do not need to be percent escaped. + +**Returns:** The encoded string, or nil if the transformation is not possible. + +### public func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? { + +Returns a new string made from the receiver by replacing characters which are +reserved in HTML forms (media type application/x-www-form-urlencoded) with +percent encoded characters. + +The W3C HTML5 specification, section 4.10.22.5 URL-encoded form +data percent encodes all characters except the following: + +- Space (0x20) is replaced by a "+" (0x2B) +- Bytes in the range 0x2A, 0x2D, 0x2E, 0x30-0x39, 0x41-0x5A, 0x5F, 0x61-0x7A +(alphanumeric + "*-._") + +**Parameter:** plusForSpace: Boolean, when true replaces space with a '+' +otherwise uses percent encoding (%20). Default is false. + +**Returns:** The encoded string, or nil if the transformation is not possible. \ No newline at end of file diff --git a/Encode/encode.xcodeproj/project.pbxproj b/Encode/encode.xcodeproj/project.pbxproj new file mode 100644 index 0000000..90a9c65 --- /dev/null +++ b/Encode/encode.xcodeproj/project.pbxproj @@ -0,0 +1,551 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53BE6B2E1C356461001C8FC9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B2D1C356461001C8FC9 /* AppDelegate.swift */; }; + 53BE6B301C356461001C8FC9 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B2F1C356461001C8FC9 /* ViewController.swift */; }; + 53BE6B331C356461001C8FC9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BE6B311C356461001C8FC9 /* Main.storyboard */; }; + 53BE6B351C356461001C8FC9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53BE6B341C356461001C8FC9 /* Assets.xcassets */; }; + 53BE6B381C356461001C8FC9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BE6B361C356461001C8FC9 /* LaunchScreen.storyboard */; }; + 53BE6B531C35E198001C8FC9 /* String+URLEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B521C35E198001C8FC9 /* String+URLEncode.swift */; }; + 53BE6B541C35E198001C8FC9 /* String+URLEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B521C35E198001C8FC9 /* String+URLEncode.swift */; }; + 53BE6B561C35E1B6001C8FC9 /* String+URLEncodeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B551C35E1B6001C8FC9 /* String+URLEncodeTest.swift */; }; + 53BE6B5E1C35E55B001C8FC9 /* encodeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B5D1C35E55B001C8FC9 /* encodeUITests.swift */; }; + 53BE6B651C35E670001C8FC9 /* String+URLEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BE6B521C35E198001C8FC9 /* String+URLEncode.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 53BE6B3F1C356462001C8FC9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 53BE6B221C356461001C8FC9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 53BE6B291C356461001C8FC9; + remoteInfo = encode; + }; + 53BE6B601C35E55B001C8FC9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 53BE6B221C356461001C8FC9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 53BE6B291C356461001C8FC9; + remoteInfo = encode; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 53BE6B2A1C356461001C8FC9 /* encode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = encode.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53BE6B2D1C356461001C8FC9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53BE6B2F1C356461001C8FC9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 53BE6B321C356461001C8FC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53BE6B341C356461001C8FC9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53BE6B371C356461001C8FC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53BE6B391C356461001C8FC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53BE6B3E1C356462001C8FC9 /* encodeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = encodeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 53BE6B441C356462001C8FC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53BE6B521C35E198001C8FC9 /* String+URLEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+URLEncode.swift"; sourceTree = ""; }; + 53BE6B551C35E1B6001C8FC9 /* String+URLEncodeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+URLEncodeTest.swift"; sourceTree = ""; }; + 53BE6B5B1C35E55B001C8FC9 /* encodeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = encodeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 53BE6B5D1C35E55B001C8FC9 /* encodeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = encodeUITests.swift; sourceTree = ""; }; + 53BE6B5F1C35E55B001C8FC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53DEA5051C36D455006334B0 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53BE6B271C356461001C8FC9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B3B1C356462001C8FC9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B581C35E55B001C8FC9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53BE6B211C356461001C8FC9 = { + isa = PBXGroup; + children = ( + 53DEA5051C36D455006334B0 /* README.md */, + 53BE6B2C1C356461001C8FC9 /* encode */, + 53BE6B411C356462001C8FC9 /* encodeTests */, + 53BE6B5C1C35E55B001C8FC9 /* encodeUITests */, + 53BE6B2B1C356461001C8FC9 /* Products */, + ); + sourceTree = ""; + }; + 53BE6B2B1C356461001C8FC9 /* Products */ = { + isa = PBXGroup; + children = ( + 53BE6B2A1C356461001C8FC9 /* encode.app */, + 53BE6B3E1C356462001C8FC9 /* encodeTests.xctest */, + 53BE6B5B1C35E55B001C8FC9 /* encodeUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 53BE6B2C1C356461001C8FC9 /* encode */ = { + isa = PBXGroup; + children = ( + 53BE6B2D1C356461001C8FC9 /* AppDelegate.swift */, + 53BE6B2F1C356461001C8FC9 /* ViewController.swift */, + 53BE6B311C356461001C8FC9 /* Main.storyboard */, + 53BE6B341C356461001C8FC9 /* Assets.xcassets */, + 53BE6B361C356461001C8FC9 /* LaunchScreen.storyboard */, + 53BE6B391C356461001C8FC9 /* Info.plist */, + 53BE6B521C35E198001C8FC9 /* String+URLEncode.swift */, + ); + path = encode; + sourceTree = ""; + }; + 53BE6B411C356462001C8FC9 /* encodeTests */ = { + isa = PBXGroup; + children = ( + 53BE6B551C35E1B6001C8FC9 /* String+URLEncodeTest.swift */, + 53BE6B441C356462001C8FC9 /* Info.plist */, + ); + path = encodeTests; + sourceTree = ""; + }; + 53BE6B5C1C35E55B001C8FC9 /* encodeUITests */ = { + isa = PBXGroup; + children = ( + 53BE6B5D1C35E55B001C8FC9 /* encodeUITests.swift */, + 53BE6B5F1C35E55B001C8FC9 /* Info.plist */, + ); + path = encodeUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53BE6B291C356461001C8FC9 /* encode */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53BE6B471C356462001C8FC9 /* Build configuration list for PBXNativeTarget "encode" */; + buildPhases = ( + 53BE6B261C356461001C8FC9 /* Sources */, + 53BE6B271C356461001C8FC9 /* Frameworks */, + 53BE6B281C356461001C8FC9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = encode; + productName = encode; + productReference = 53BE6B2A1C356461001C8FC9 /* encode.app */; + productType = "com.apple.product-type.application"; + }; + 53BE6B3D1C356462001C8FC9 /* encodeTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53BE6B4A1C356462001C8FC9 /* Build configuration list for PBXNativeTarget "encodeTests" */; + buildPhases = ( + 53BE6B3A1C356462001C8FC9 /* Sources */, + 53BE6B3B1C356462001C8FC9 /* Frameworks */, + 53BE6B3C1C356462001C8FC9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 53BE6B401C356462001C8FC9 /* PBXTargetDependency */, + ); + name = encodeTests; + productName = encodeTests; + productReference = 53BE6B3E1C356462001C8FC9 /* encodeTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 53BE6B5A1C35E55B001C8FC9 /* encodeUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53BE6B621C35E55B001C8FC9 /* Build configuration list for PBXNativeTarget "encodeUITests" */; + buildPhases = ( + 53BE6B571C35E55B001C8FC9 /* Sources */, + 53BE6B581C35E55B001C8FC9 /* Frameworks */, + 53BE6B591C35E55B001C8FC9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 53BE6B611C35E55B001C8FC9 /* PBXTargetDependency */, + ); + name = encodeUITests; + productName = encodeUITests; + productReference = 53BE6B5B1C35E55B001C8FC9 /* encodeUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53BE6B221C356461001C8FC9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53BE6B291C356461001C8FC9 = { + CreatedOnToolsVersion = 7.2; + DevelopmentTeam = LCC2J94N44; + }; + 53BE6B3D1C356462001C8FC9 = { + CreatedOnToolsVersion = 7.2; + TestTargetID = 53BE6B291C356461001C8FC9; + }; + 53BE6B5A1C35E55B001C8FC9 = { + CreatedOnToolsVersion = 7.2; + TestTargetID = 53BE6B291C356461001C8FC9; + }; + }; + }; + buildConfigurationList = 53BE6B251C356461001C8FC9 /* Build configuration list for PBXProject "encode" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53BE6B211C356461001C8FC9; + productRefGroup = 53BE6B2B1C356461001C8FC9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53BE6B291C356461001C8FC9 /* encode */, + 53BE6B3D1C356462001C8FC9 /* encodeTests */, + 53BE6B5A1C35E55B001C8FC9 /* encodeUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53BE6B281C356461001C8FC9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BE6B381C356461001C8FC9 /* LaunchScreen.storyboard in Resources */, + 53BE6B351C356461001C8FC9 /* Assets.xcassets in Resources */, + 53BE6B331C356461001C8FC9 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B3C1C356462001C8FC9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B591C35E55B001C8FC9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53BE6B261C356461001C8FC9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BE6B301C356461001C8FC9 /* ViewController.swift in Sources */, + 53BE6B531C35E198001C8FC9 /* String+URLEncode.swift in Sources */, + 53BE6B2E1C356461001C8FC9 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B3A1C356462001C8FC9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BE6B561C35E1B6001C8FC9 /* String+URLEncodeTest.swift in Sources */, + 53BE6B541C35E198001C8FC9 /* String+URLEncode.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BE6B571C35E55B001C8FC9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BE6B651C35E670001C8FC9 /* String+URLEncode.swift in Sources */, + 53BE6B5E1C35E55B001C8FC9 /* encodeUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 53BE6B401C356462001C8FC9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 53BE6B291C356461001C8FC9 /* encode */; + targetProxy = 53BE6B3F1C356462001C8FC9 /* PBXContainerItemProxy */; + }; + 53BE6B611C35E55B001C8FC9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 53BE6B291C356461001C8FC9 /* encode */; + targetProxy = 53BE6B601C35E55B001C8FC9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 53BE6B311C356461001C8FC9 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53BE6B321C356461001C8FC9 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53BE6B361C356461001C8FC9 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53BE6B371C356461001C8FC9 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53BE6B451C356462001C8FC9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53BE6B461C356462001C8FC9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53BE6B481C356462001C8FC9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = encode/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encode; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 53BE6B491C356462001C8FC9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = encode/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encode; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 53BE6B4B1C356462001C8FC9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = encodeTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encodeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/encode.app/encode"; + }; + name = Debug; + }; + 53BE6B4C1C356462001C8FC9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = encodeTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encodeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/encode.app/encode"; + }; + name = Release; + }; + 53BE6B631C35E55B001C8FC9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = encodeUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encodeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = encode; + USES_XCTRUNNER = YES; + }; + name = Debug; + }; + 53BE6B641C35E55B001C8FC9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = encodeUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.encodeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = encode; + USES_XCTRUNNER = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53BE6B251C356461001C8FC9 /* Build configuration list for PBXProject "encode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BE6B451C356462001C8FC9 /* Debug */, + 53BE6B461C356462001C8FC9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BE6B471C356462001C8FC9 /* Build configuration list for PBXNativeTarget "encode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BE6B481C356462001C8FC9 /* Debug */, + 53BE6B491C356462001C8FC9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BE6B4A1C356462001C8FC9 /* Build configuration list for PBXNativeTarget "encodeTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BE6B4B1C356462001C8FC9 /* Debug */, + 53BE6B4C1C356462001C8FC9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BE6B621C35E55B001C8FC9 /* Build configuration list for PBXNativeTarget "encodeUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BE6B631C35E55B001C8FC9 /* Debug */, + 53BE6B641C35E55B001C8FC9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53BE6B221C356461001C8FC9 /* Project object */; +} diff --git a/Encode/encode/AppDelegate.swift b/Encode/encode/AppDelegate.swift new file mode 100644 index 0000000..7f2b252 --- /dev/null +++ b/Encode/encode/AppDelegate.swift @@ -0,0 +1,41 @@ +// +// AppDelegate.swift +// encode +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? +} + diff --git a/Encode/encode/Assets.xcassets/AppIcon.appiconset/Contents.json b/Encode/encode/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/Encode/encode/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Encode/encode/Base.lproj/LaunchScreen.storyboard b/Encode/encode/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..331e43e --- /dev/null +++ b/Encode/encode/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Encode/encode/Base.lproj/Main.storyboard b/Encode/encode/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d39fa46 --- /dev/null +++ b/Encode/encode/Base.lproj/Main.storyboard @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Encode/encode/Info.plist b/Encode/encode/Info.plist new file mode 100644 index 0000000..40c6215 --- /dev/null +++ b/Encode/encode/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Encode/encode/String+URLEncode.swift b/Encode/encode/String+URLEncode.swift new file mode 100644 index 0000000..45a1157 --- /dev/null +++ b/Encode/encode/String+URLEncode.swift @@ -0,0 +1,99 @@ +// +// String+URLEncode.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +/** + A String extension that provides percent encoding of URL + strings following RFC 3986 or the W3C HTML specification. + */ + +extension String { + + /** + Returns a new string made from the receiver by replacing characters which are + reserved in a URI query with percent encoded characters. + + The following characters are not considered reserved in a URI query + by RFC 3986: + + - Alpha "a...z" "A...Z" + - Numberic "0...9" + - Unreserved "-._~" + + In addition the reserved characters "/" and "?" have no reserved purpose in the + query component of a URI so do not need to be percent escaped. + + - Returns: The encoded string, or nil if the transformation is not possible. + */ + + public func stringByAddingPercentEncodingForRFC3986() -> String? { + let unreserved = "-._~/?" + let allowedCharacterSet = NSMutableCharacterSet.alphanumeric() + allowedCharacterSet.addCharacters(in: unreserved) + return addingPercentEncoding(withAllowedCharacters: allowedCharacterSet as CharacterSet) + } + + /** + Returns a new string made from the receiver by replacing characters which are + reserved in HTML forms (media type application/x-www-form-urlencoded) with + percent encoded characters. + + The W3C HTML5 specification, section 4.10.22.5 URL-encoded form + data percent encodes all characters except the following: + + - Space (0x20) is replaced by a "+" (0x2B) + - Bytes in the range 0x2A, 0x2D, 0x2E, 0x30-0x39, 0x41-0x5A, 0x5F, 0x61-0x7A + (alphanumeric + "*-._") + + - Parameter plusForSpace: Boolean, when true replaces space with a '+' + otherwise uses percent encoding (%20). Default is false. + + - Returns: The encoded string, or nil if the transformation is not possible. + */ + + public func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? { + let unreserved = "*-._" + let allowedCharacterSet = NSMutableCharacterSet.alphanumeric() + allowedCharacterSet.addCharacters(in: unreserved) + + if plusForSpace { + allowedCharacterSet.addCharacters(in: " ") + } + + var encoded = addingPercentEncoding(withAllowedCharacters: allowedCharacterSet as CharacterSet) + if plusForSpace { + encoded = encoded?.replacingOccurrences(of: " ", with: "+") + } + return encoded + } +} diff --git a/Encode/encode/ViewController.swift b/Encode/encode/ViewController.swift new file mode 100644 index 0000000..462c88c --- /dev/null +++ b/Encode/encode/ViewController.swift @@ -0,0 +1,61 @@ +// +// ViewController.swift +// encode +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2016-2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class ViewController: UIViewController { + + @IBOutlet weak var rfc3986Output: UILabel! + @IBOutlet weak var formOutput: UILabel! + @IBOutlet weak var textInput: UITextField! + @IBOutlet weak var plusSwitch: UISwitch! + + @IBAction func plusValueChanged(sender: UISwitch) { + updateOutputLabels() + } + + func updateOutputLabels() { + let input = textInput.text + let usePlusForSpace = plusSwitch.isOn + rfc3986Output.text = input?.stringByAddingPercentEncodingForRFC3986() + formOutput.text = input?.stringByAddingPercentEncodingForFormData(plusForSpace: usePlusForSpace) + } +} + +extension ViewController: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + updateOutputLabels() + return true + } +} + diff --git a/Encode/encodeTests/Info.plist b/Encode/encodeTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/Encode/encodeTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Encode/encodeTests/String+URLEncodeTest.swift b/Encode/encodeTests/String+URLEncodeTest.swift new file mode 100644 index 0000000..14af416 --- /dev/null +++ b/Encode/encodeTests/String+URLEncodeTest.swift @@ -0,0 +1,134 @@ +// +// String+URLEncodeTest.swift +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2016-2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import XCTest + +class URLEncodeTest: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testRFC3986AlphaNumericNotEncoded() { + let input = "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789" + let output = input.stringByAddingPercentEncodingForRFC3986() + XCTAssertEqual(input, output) + } + + func testFormAlphaNumericNotEncoded() { + let input = "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789" + let output = input.stringByAddingPercentEncodingForFormData() + XCTAssertEqual(input, output) + } + + func testRFC3986UnreservedNotEncoded() { + let input = "-._~" + let output = input.stringByAddingPercentEncodingForRFC3986() + XCTAssertEqual(input, output) + } + + func testRFC3986SlashQuestionNotEncoded() { + let input = "/?" + let output = input.stringByAddingPercentEncodingForRFC3986() + XCTAssertEqual(input, output) + } + + func testFormUnreservedNotEncoded() { + let input = "*-._" + let output = input.stringByAddingPercentEncodingForFormData() + XCTAssertEqual(input, output) + } + + func testQuerySpacePercentEncoded() { + let input = "one two" + let output = input.stringByAddingPercentEncodingForRFC3986() + let expected = "one%20two" + XCTAssertEqual(expected, output) + } + + func testFormSpacePercentEncoded() { + let input = "one two" + let output = input.stringByAddingPercentEncodingForFormData() + let expected = "one%20two" + XCTAssertEqual(expected, output) + } + + func testFormSpacePlusEncoded() { + let input = "one two" + let output = input.stringByAddingPercentEncodingForFormData(plusForSpace: true) + let expected = "one+two" + XCTAssertEqual(expected, output) + } + + func testFormPlusIsPercentEncoded() { + let input = "one+two" + let output = input.stringByAddingPercentEncodingForFormData(plusForSpace: true) + let expected = "one%2Btwo" + XCTAssertEqual(expected, output) + } + + func testQueryPercentPercentEncoded() { + let input = "%" + let output = input.stringByAddingPercentEncodingForRFC3986() + let expected = "%25" + XCTAssertEqual(expected, output) + } + + func testFormPercentPercentEncoded() { + let input = "%" + let output = input.stringByAddingPercentEncodingForFormData() + let expected = "%25" + XCTAssertEqual(expected, output) + } + + func testQueryReservedPercentEncoded() { + let input = "!#$&'()*+,:;=@[]" + let output = input.stringByAddingPercentEncodingForRFC3986() + let expected = "%21%23%24%26%27%28%29%2A%2B%2C%3A%3B%3D%40%5B%5D" + XCTAssertEqual(expected, output) + } + + func testFormReservedPercentEncoded() { + let input = "!#$&'()+,/:;=?@[]" + let output = input.stringByAddingPercentEncodingForFormData() + let expected = "%21%23%24%26%27%28%29%2B%2C%2F%3A%3B%3D%3F%40%5B%5D" + XCTAssertEqual(expected, output) + } +} diff --git a/Encode/encodeUITests/Info.plist b/Encode/encodeUITests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/Encode/encodeUITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Encode/encodeUITests/encodeUITests.swift b/Encode/encodeUITests/encodeUITests.swift new file mode 100644 index 0000000..8abdde3 --- /dev/null +++ b/Encode/encodeUITests/encodeUITests.swift @@ -0,0 +1,86 @@ +// +// encodeUITests.swift +// encodeUITests +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2016-2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import XCTest + +class encodeUITests: XCTestCase { + + override func setUp() { + super.setUp() + continueAfterFailure = false + XCUIApplication().launch() + } + + func testOutputUpdated() { + let app = XCUIApplication() + let input = "one two" + let expectedRFC3986 = input.stringByAddingPercentEncodingForRFC3986() + let expectedForm = input.stringByAddingPercentEncodingForFormData() + + let textToEncodeTextField = app.textFields["InputText"] + textToEncodeTextField.tap() + textToEncodeTextField.typeText("\(input)\r") + + let outputRFC3986 = app.staticTexts["RFC3968Output"] + XCTAssertEqual(expectedRFC3986, outputRFC3986.label) + + let outputForm = app.staticTexts["FormOutput"] + XCTAssertEqual(expectedForm, outputForm.label) + } + + func testPlusForSpaceSwitch() { + let app = XCUIApplication() + let input = "one two" + let expectedRFC3986 = input.stringByAddingPercentEncodingForRFC3986() + let expectedForm = input.stringByAddingPercentEncodingForFormData() + let expectedPlusForm = input.stringByAddingPercentEncodingForFormData(plusForSpace: true) + + let textToEncodeTextField = app.textFields["InputText"] + textToEncodeTextField.tap() + textToEncodeTextField.typeText("\(input)\r") + + let outputRFC3986 = app.staticTexts["RFC3968Output"] + XCTAssertEqual(expectedRFC3986, outputRFC3986.label) + + let outputForm = app.staticTexts["FormOutput"] + XCTAssertEqual(expectedForm, outputForm.label) + + app.switches["PlusSwitch"].tap() + XCTAssertEqual(expectedRFC3986, outputRFC3986.label) + XCTAssertEqual(expectedPlusForm, outputForm.label) + + app.switches["PlusSwitch"].tap() + XCTAssertEqual(expectedRFC3986, outputRFC3986.label) + XCTAssertEqual(expectedForm, outputForm.label) + } +} diff --git a/GridView/GridView.xcodeproj/project.pbxproj b/GridView/GridView.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8324803 --- /dev/null +++ b/GridView/GridView.xcodeproj/project.pbxproj @@ -0,0 +1,480 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 531CCB8B1EAA45D2008349F4 /* GridViewUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 531CCB891EAA45D2008349F4 /* GridViewUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 531CCB8F1EAA475A008349F4 /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5366BC771EA8E15E006A06E5 /* GridView.swift */; }; + 5366BC661EA8DF80006A06E5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5366BC651EA8DF80006A06E5 /* AppDelegate.swift */; }; + 5366BC6B1EA8DF80006A06E5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5366BC691EA8DF80006A06E5 /* Main.storyboard */; }; + 5366BC6D1EA8DF80006A06E5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5366BC6C1EA8DF80006A06E5 /* Assets.xcassets */; }; + 5366BC701EA8DF80006A06E5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5366BC6E1EA8DF80006A06E5 /* LaunchScreen.storyboard */; }; + 5366BC781EA8E15E006A06E5 /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5366BC771EA8E15E006A06E5 /* GridView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 531CCB871EAA45D2008349F4 /* GridViewUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GridViewUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 531CCB891EAA45D2008349F4 /* GridViewUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GridViewUI.h; sourceTree = ""; }; + 531CCB8A1EAA45D2008349F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5366BC621EA8DF80006A06E5 /* GridView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GridView.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5366BC651EA8DF80006A06E5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5366BC6A1EA8DF80006A06E5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5366BC6C1EA8DF80006A06E5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5366BC6F1EA8DF80006A06E5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5366BC711EA8DF80006A06E5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5366BC771EA8E15E006A06E5 /* GridView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 531CCB831EAA45D2008349F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5366BC5F1EA8DF80006A06E5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 531CCB881EAA45D2008349F4 /* GridViewUI */ = { + isa = PBXGroup; + children = ( + 531CCB891EAA45D2008349F4 /* GridViewUI.h */, + 531CCB8A1EAA45D2008349F4 /* Info.plist */, + ); + path = GridViewUI; + sourceTree = ""; + }; + 5366BC591EA8DF80006A06E5 = { + isa = PBXGroup; + children = ( + 5366BC641EA8DF80006A06E5 /* GridView */, + 531CCB881EAA45D2008349F4 /* GridViewUI */, + 5366BC631EA8DF80006A06E5 /* Products */, + ); + sourceTree = ""; + }; + 5366BC631EA8DF80006A06E5 /* Products */ = { + isa = PBXGroup; + children = ( + 5366BC621EA8DF80006A06E5 /* GridView.app */, + 531CCB871EAA45D2008349F4 /* GridViewUI.framework */, + ); + name = Products; + sourceTree = ""; + }; + 5366BC641EA8DF80006A06E5 /* GridView */ = { + isa = PBXGroup; + children = ( + 5366BC651EA8DF80006A06E5 /* AppDelegate.swift */, + 5366BC691EA8DF80006A06E5 /* Main.storyboard */, + 5366BC771EA8E15E006A06E5 /* GridView.swift */, + 5366BC6C1EA8DF80006A06E5 /* Assets.xcassets */, + 5366BC6E1EA8DF80006A06E5 /* LaunchScreen.storyboard */, + 5366BC711EA8DF80006A06E5 /* Info.plist */, + ); + path = GridView; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 531CCB841EAA45D2008349F4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 531CCB8B1EAA45D2008349F4 /* GridViewUI.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 531CCB861EAA45D2008349F4 /* GridViewUI */ = { + isa = PBXNativeTarget; + buildConfigurationList = 531CCB8E1EAA45D2008349F4 /* Build configuration list for PBXNativeTarget "GridViewUI" */; + buildPhases = ( + 531CCB821EAA45D2008349F4 /* Sources */, + 531CCB831EAA45D2008349F4 /* Frameworks */, + 531CCB841EAA45D2008349F4 /* Headers */, + 531CCB851EAA45D2008349F4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GridViewUI; + productName = GridViewUI; + productReference = 531CCB871EAA45D2008349F4 /* GridViewUI.framework */; + productType = "com.apple.product-type.framework"; + }; + 5366BC611EA8DF80006A06E5 /* GridView */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5366BC741EA8DF80006A06E5 /* Build configuration list for PBXNativeTarget "GridView" */; + buildPhases = ( + 5366BC5E1EA8DF80006A06E5 /* Sources */, + 5366BC5F1EA8DF80006A06E5 /* Frameworks */, + 5366BC601EA8DF80006A06E5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GridView; + productName = GridView; + productReference = 5366BC621EA8DF80006A06E5 /* GridView.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5366BC5A1EA8DF80006A06E5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 531CCB861EAA45D2008349F4 = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + 5366BC611EA8DF80006A06E5 = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 5366BC5D1EA8DF80006A06E5 /* Build configuration list for PBXProject "GridView" */; + compatibilityVersion = "Xcode 10.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5366BC591EA8DF80006A06E5; + productRefGroup = 5366BC631EA8DF80006A06E5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5366BC611EA8DF80006A06E5 /* GridView */, + 531CCB861EAA45D2008349F4 /* GridViewUI */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 531CCB851EAA45D2008349F4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5366BC601EA8DF80006A06E5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5366BC701EA8DF80006A06E5 /* LaunchScreen.storyboard in Resources */, + 5366BC6D1EA8DF80006A06E5 /* Assets.xcassets in Resources */, + 5366BC6B1EA8DF80006A06E5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 531CCB821EAA45D2008349F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 531CCB8F1EAA475A008349F4 /* GridView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5366BC5E1EA8DF80006A06E5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5366BC781EA8E15E006A06E5 /* GridView.swift in Sources */, + 5366BC661EA8DF80006A06E5 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5366BC691EA8DF80006A06E5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5366BC6A1EA8DF80006A06E5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5366BC6E1EA8DF80006A06E5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5366BC6F1EA8DF80006A06E5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 531CCB8C1EAA45D2008349F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = LCC2J94N44; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = GridViewUI/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.GridViewUI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 531CCB8D1EAA45D2008349F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = LCC2J94N44; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = GridViewUI/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.GridViewUI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 5366BC721EA8DF80006A06E5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5366BC731EA8DF80006A06E5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5366BC751EA8DF80006A06E5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = GridView/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.GridView; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5366BC761EA8DF80006A06E5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = GridView/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.GridView; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 531CCB8E1EAA45D2008349F4 /* Build configuration list for PBXNativeTarget "GridViewUI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 531CCB8C1EAA45D2008349F4 /* Debug */, + 531CCB8D1EAA45D2008349F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5366BC5D1EA8DF80006A06E5 /* Build configuration list for PBXProject "GridView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5366BC721EA8DF80006A06E5 /* Debug */, + 5366BC731EA8DF80006A06E5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5366BC741EA8DF80006A06E5 /* Build configuration list for PBXNativeTarget "GridView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5366BC751EA8DF80006A06E5 /* Debug */, + 5366BC761EA8DF80006A06E5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5366BC5A1EA8DF80006A06E5 /* Project object */; +} diff --git a/GridView/GridView.xcworkspace/contents.xcworkspacedata b/GridView/GridView.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..8a969d2 --- /dev/null +++ b/GridView/GridView.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/GridView/GridView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GridView/GridView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/GridView/GridView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GridView/GridView/AppDelegate.swift b/GridView/GridView/AppDelegate.swift new file mode 100644 index 0000000..e757b1f --- /dev/null +++ b/GridView/GridView/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// GridView +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/GridView/GridView/Assets.xcassets/AppIcon.appiconset/Contents.json b/GridView/GridView/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/GridView/GridView/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/GridView/GridView/Base.lproj/LaunchScreen.storyboard b/GridView/GridView/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..0295d5f --- /dev/null +++ b/GridView/GridView/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GridView/GridView/Base.lproj/Main.storyboard b/GridView/GridView/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2bb0240 --- /dev/null +++ b/GridView/GridView/Base.lproj/Main.storyboard @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GridView/GridView/GridView.swift b/GridView/GridView/GridView.swift new file mode 100644 index 0000000..ad3349d --- /dev/null +++ b/GridView/GridView/GridView.swift @@ -0,0 +1,92 @@ +// GridView.swift +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/// `GridView` is a custom `UIView` subclass that draws +/// a grid of evenly spaced lines in the bounds of the view. +/// Attention: You probably want to set the `contentMode` to `.redraw`. + +@IBDesignable +public class GridView: UIView { + /// The number of horizontal rows - default is 1. + @IBInspectable public var rowCount: Int = 1 { didSet { setNeedsDisplay() } } + + /// The number of vertical columns - default is 1. + @IBInspectable public var columnCount: Int = 1 { didSet { setNeedsDisplay() } } + + /// The grid line color - default is red. + @IBInspectable public var lineColor: UIColor = .red { didSet { setNeedsDisplay() } } + + /// The grid line width - default is 1 point. + @IBInspectable public var lineWidth: CGFloat = 1.0 { didSet { setNeedsDisplay() } } + + public override func draw(_ rect: CGRect) { + lineColor.set() + rowPath?.stroke() + columnPath?.stroke() + } + + private var rowPath: UIBezierPath? { + guard rowCount > 0 else { + return nil + } + + let rowPath = UIBezierPath() + rowPath.lineWidth = lineWidth + let rowHeight = bounds.size.height / CGFloat(rowCount + 1) + for row in 1...rowCount { + let y = rowHeight * CGFloat(row) + let startPoint = CGPoint(x: bounds.minX, y: y) + let endPoint = CGPoint(x: bounds.maxX, y: y) + rowPath.move(to: startPoint) + rowPath.addLine(to: endPoint) + } + return rowPath + } + + private var columnPath: UIBezierPath? { + guard columnCount > 0 else { + return nil + } + + let columnPath = UIBezierPath() + columnPath.lineWidth = lineWidth + let columnWidth = bounds.size.width / CGFloat(columnCount + 1) + for row in 1...columnCount { + let x = columnWidth * CGFloat(row) + let startPoint = CGPoint(x: x, y: bounds.minY) + let endPoint = CGPoint(x: x, y: bounds.maxY) + columnPath.move(to: startPoint) + columnPath.addLine(to: endPoint) + } + return columnPath + } +} diff --git a/GridView/GridView/Info.plist b/GridView/GridView/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/GridView/GridView/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/GridView/GridViewUI/GridViewUI.h b/GridView/GridViewUI/GridViewUI.h new file mode 100644 index 0000000..d02e371 --- /dev/null +++ b/GridView/GridViewUI/GridViewUI.h @@ -0,0 +1,19 @@ +// +// GridViewUI.h +// GridViewUI +// +// Created by Keith Harrison on 21/04/2017. +// Copyright © 2017 Keith Harrison. All rights reserved. +// + +#import + +//! Project version number for GridViewUI. +FOUNDATION_EXPORT double GridViewUIVersionNumber; + +//! Project version string for GridViewUI. +FOUNDATION_EXPORT const unsigned char GridViewUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/GridView/GridViewUI/Info.plist b/GridView/GridViewUI/Info.plist new file mode 100644 index 0000000..fbe1e6b --- /dev/null +++ b/GridView/GridViewUI/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/GridView/README.md b/GridView/README.md new file mode 100644 index 0000000..73c2a51 --- /dev/null +++ b/GridView/README.md @@ -0,0 +1,9 @@ +### Adding a Playground to an Xcode Project + +Example setup of a workspace containing a playground and project. The resources +in the project that need to be accessible from the playground are added to a +framework. + +See the following blog post for a step-by-step guide to creating this setup + ++ [Adding playgrounds to Xcode projects](https://useyourloaf.com/blog/adding-playgrounds-to-xcode-projects/) diff --git a/GridView/UIPlayground.playground/Contents.swift b/GridView/UIPlayground.playground/Contents.swift new file mode 100644 index 0000000..b9594ed --- /dev/null +++ b/GridView/UIPlayground.playground/Contents.swift @@ -0,0 +1,16 @@ +//: PlaygroundUI +import UIKit +import GridViewUI +import PlaygroundSupport + +//: Demo using the grid view +let grid = GridView() +grid.backgroundColor = .lightGray +grid.rowCount = 3 +grid.columnCount = 3 +grid.lineColor = .blue +grid.lineWidth = 5 + +//: Show in live view +grid.frame = CGRect(x: 0, y: 0, width: 200, height: 300) +PlaygroundPage.current.liveView = grid \ No newline at end of file diff --git a/GridView/UIPlayground.playground/contents.xcplayground b/GridView/UIPlayground.playground/contents.xcplayground new file mode 100644 index 0000000..5da2641 --- /dev/null +++ b/GridView/UIPlayground.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/GridView/UIPlayground.playground/timeline.xctimeline b/GridView/UIPlayground.playground/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/GridView/UIPlayground.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Huckleberry/Huckleberry.xcodeproj/project.pbxproj b/Huckleberry/Huckleberry.xcodeproj/project.pbxproj new file mode 100644 index 0000000..cb5ed1a --- /dev/null +++ b/Huckleberry/Huckleberry.xcodeproj/project.pbxproj @@ -0,0 +1,367 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 5325894623C911B9008ABE63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5325894823C911B9008ABE63 /* LaunchScreen.storyboard */; }; + 53512CFC18AC3A0300A74F57 /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53512CFB18AC3A0300A74F57 /* UYLTableViewController.m */; }; + 535C803818AD71750039A2B3 /* SourceData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 535C803718AD71750039A2B3 /* SourceData.plist */; }; + 5363F6D618AADBF6001CBD3A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5363F6D518AADBF6001CBD3A /* Foundation.framework */; }; + 5363F6D818AADBF6001CBD3A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5363F6D718AADBF6001CBD3A /* CoreGraphics.framework */; }; + 5363F6DA18AADBF6001CBD3A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5363F6D918AADBF6001CBD3A /* UIKit.framework */; }; + 5363F6E018AADBF6001CBD3A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5363F6DE18AADBF6001CBD3A /* InfoPlist.strings */; }; + 5363F6E218AADBF6001CBD3A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5363F6E118AADBF6001CBD3A /* main.m */; }; + 5363F6E618AADBF6001CBD3A /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5363F6E518AADBF6001CBD3A /* UYLAppDelegate.m */; }; + 5363F6E918AADBF6001CBD3A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5363F6E718AADBF6001CBD3A /* Main.storyboard */; }; + 5363F6EE18AADBF6001CBD3A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5363F6ED18AADBF6001CBD3A /* Images.xcassets */; }; + 53A8DCA618AC37530053ABAF /* UYLTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A8DCA518AC37530053ABAF /* UYLTextCell.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5325894723C911B9008ABE63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53512CFA18AC3A0300A74F57 /* UYLTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTableViewController.h; sourceTree = ""; }; + 53512CFB18AC3A0300A74F57 /* UYLTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTableViewController.m; sourceTree = ""; }; + 535C803718AD71750039A2B3 /* SourceData.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SourceData.plist; sourceTree = ""; }; + 536259D91F41DEFD00616356 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 5363F6D218AADBF6001CBD3A /* Huckleberry.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Huckleberry.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5363F6D518AADBF6001CBD3A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5363F6D718AADBF6001CBD3A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5363F6D918AADBF6001CBD3A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5363F6DD18AADBF6001CBD3A /* Huckleberry-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Huckleberry-Info.plist"; sourceTree = ""; }; + 5363F6DF18AADBF6001CBD3A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5363F6E118AADBF6001CBD3A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5363F6E418AADBF6001CBD3A /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 5363F6E518AADBF6001CBD3A /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 5363F6E818AADBF6001CBD3A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5363F6ED18AADBF6001CBD3A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5363F6F418AADBF6001CBD3A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 53A8DCA418AC37530053ABAF /* UYLTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTextCell.h; sourceTree = ""; }; + 53A8DCA518AC37530053ABAF /* UYLTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTextCell.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5363F6CF18AADBF6001CBD3A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5363F6D818AADBF6001CBD3A /* CoreGraphics.framework in Frameworks */, + 5363F6DA18AADBF6001CBD3A /* UIKit.framework in Frameworks */, + 5363F6D618AADBF6001CBD3A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5363F6C918AADBF6001CBD3A = { + isa = PBXGroup; + children = ( + 536259D91F41DEFD00616356 /* README.md */, + 5363F6DB18AADBF6001CBD3A /* Huckleberry */, + 5363F6D418AADBF6001CBD3A /* Frameworks */, + 5363F6D318AADBF6001CBD3A /* Products */, + ); + sourceTree = ""; + }; + 5363F6D318AADBF6001CBD3A /* Products */ = { + isa = PBXGroup; + children = ( + 5363F6D218AADBF6001CBD3A /* Huckleberry.app */, + ); + name = Products; + sourceTree = ""; + }; + 5363F6D418AADBF6001CBD3A /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5363F6D518AADBF6001CBD3A /* Foundation.framework */, + 5363F6D718AADBF6001CBD3A /* CoreGraphics.framework */, + 5363F6D918AADBF6001CBD3A /* UIKit.framework */, + 5363F6F418AADBF6001CBD3A /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5363F6DB18AADBF6001CBD3A /* Huckleberry */ = { + isa = PBXGroup; + children = ( + 5363F6E418AADBF6001CBD3A /* UYLAppDelegate.h */, + 5363F6E518AADBF6001CBD3A /* UYLAppDelegate.m */, + 53A8DCA418AC37530053ABAF /* UYLTextCell.h */, + 53A8DCA518AC37530053ABAF /* UYLTextCell.m */, + 53512CFA18AC3A0300A74F57 /* UYLTableViewController.h */, + 53512CFB18AC3A0300A74F57 /* UYLTableViewController.m */, + 5363F6E718AADBF6001CBD3A /* Main.storyboard */, + 5325894823C911B9008ABE63 /* LaunchScreen.storyboard */, + 5363F6ED18AADBF6001CBD3A /* Images.xcassets */, + 5363F6DC18AADBF6001CBD3A /* Supporting Files */, + ); + path = Huckleberry; + sourceTree = ""; + }; + 5363F6DC18AADBF6001CBD3A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 535C803718AD71750039A2B3 /* SourceData.plist */, + 5363F6DD18AADBF6001CBD3A /* Huckleberry-Info.plist */, + 5363F6DE18AADBF6001CBD3A /* InfoPlist.strings */, + 5363F6E118AADBF6001CBD3A /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5363F6D118AADBF6001CBD3A /* Huckleberry */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5363F70418AADBF6001CBD3A /* Build configuration list for PBXNativeTarget "Huckleberry" */; + buildPhases = ( + 5363F6CE18AADBF6001CBD3A /* Sources */, + 5363F6CF18AADBF6001CBD3A /* Frameworks */, + 5363F6D018AADBF6001CBD3A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Huckleberry; + productName = Huckleberry; + productReference = 5363F6D218AADBF6001CBD3A /* Huckleberry.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5363F6CA18AADBF6001CBD3A /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 5363F6CD18AADBF6001CBD3A /* Build configuration list for PBXProject "Huckleberry" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5363F6C918AADBF6001CBD3A; + productRefGroup = 5363F6D318AADBF6001CBD3A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5363F6D118AADBF6001CBD3A /* Huckleberry */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5363F6D018AADBF6001CBD3A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5363F6EE18AADBF6001CBD3A /* Images.xcassets in Resources */, + 535C803818AD71750039A2B3 /* SourceData.plist in Resources */, + 5363F6E018AADBF6001CBD3A /* InfoPlist.strings in Resources */, + 5325894623C911B9008ABE63 /* LaunchScreen.storyboard in Resources */, + 5363F6E918AADBF6001CBD3A /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5363F6CE18AADBF6001CBD3A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53512CFC18AC3A0300A74F57 /* UYLTableViewController.m in Sources */, + 5363F6E218AADBF6001CBD3A /* main.m in Sources */, + 53A8DCA618AC37530053ABAF /* UYLTextCell.m in Sources */, + 5363F6E618AADBF6001CBD3A /* UYLAppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5325894823C911B9008ABE63 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5325894723C911B9008ABE63 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 5363F6DE18AADBF6001CBD3A /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5363F6DF18AADBF6001CBD3A /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5363F6E718AADBF6001CBD3A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5363F6E818AADBF6001CBD3A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5363F70218AADBF6001CBD3A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5363F70318AADBF6001CBD3A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5363F70518AADBF6001CBD3A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "Huckleberry/Huckleberry-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5363F70618AADBF6001CBD3A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "Huckleberry/Huckleberry-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5363F6CD18AADBF6001CBD3A /* Build configuration list for PBXProject "Huckleberry" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5363F70218AADBF6001CBD3A /* Debug */, + 5363F70318AADBF6001CBD3A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5363F70418AADBF6001CBD3A /* Build configuration list for PBXNativeTarget "Huckleberry" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5363F70518AADBF6001CBD3A /* Debug */, + 5363F70618AADBF6001CBD3A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5363F6CA18AADBF6001CBD3A /* Project object */; +} diff --git a/Huckleberry/Huckleberry/Base.lproj/LaunchScreen.storyboard b/Huckleberry/Huckleberry/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..867027e --- /dev/null +++ b/Huckleberry/Huckleberry/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Huckleberry/Huckleberry/Base.lproj/Main.storyboard b/Huckleberry/Huckleberry/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e3d6b76 --- /dev/null +++ b/Huckleberry/Huckleberry/Base.lproj/Main.storyboard @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TwitterSearch/TwitterSearch/TwitterSearch-Info.plist b/Huckleberry/Huckleberry/Huckleberry-Info.plist similarity index 80% rename from TwitterSearch/TwitterSearch/TwitterSearch-Info.plist rename to Huckleberry/Huckleberry/Huckleberry-Info.plist index da68ef9..3f28fd9 100644 --- a/TwitterSearch/TwitterSearch/TwitterSearch-Info.plist +++ b/Huckleberry/Huckleberry/Huckleberry-Info.plist @@ -8,10 +8,8 @@ ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} - CFBundleIconFile - CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -26,8 +24,14 @@ 1.0 LSRequiresIPhoneOS - NSMainNibFile - MainWindow + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/Huckleberry/Huckleberry/Images.xcassets/AppIcon.appiconset/Contents.json b/Huckleberry/Huckleberry/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..19882d5 --- /dev/null +++ b/Huckleberry/Huckleberry/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Huckleberry/Huckleberry/Images.xcassets/Contents.json b/Huckleberry/Huckleberry/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Huckleberry/Huckleberry/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Huckleberry/Huckleberry/SourceData.plist b/Huckleberry/Huckleberry/SourceData.plist new file mode 100644 index 0000000..a824d0a --- /dev/null +++ b/Huckleberry/Huckleberry/SourceData.plist @@ -0,0 +1,2003 @@ + + + + + Chapter I + YOU don't know about me without you have read a book by the name of The Adventures of Tom Sawyer; but that ain't no matter. + That book was made by Mr. Mark Twain, and he told the truth, mainly. + There was things which he stretched, but mainly he told the truth. + That is nothing. + I never seen anybody but lied one time or another, without it was Aunt Polly, or the widow, or maybe Mary. + Aunt Polly—Tom's Aunt Polly, she is—and Mary, and the Widow Douglas is all told about in that book, which is mostly a true book, with some stretchers, as I said before. + Now the way that the book winds up is this: Tom and me found the money that the robbers hid in the cave, and it made us rich. + We got six thousand dollars apiece—all gold. + It was an awful sight of money when it was piled up. + Well, Judge Thatcher he took it and put it out at interest, and it fetched us a dollar a day apiece all the year round—more than a body could tell what to do with. + The Widow Douglas she took me for her son, and allowed she would sivilize me; but it was rough living in the house all the time, considering how dismal regular and decent the widow was in all her ways; and so when I couldn't stand it no longer I lit out. + I got into my old rags and my sugar-hogshead again, and was free and satisfied. + But Tom Sawyer he hunted me up and said he was going to start a band of robbers, and I might join if I would go back to the widow and be respectable. + So I went back. + The widow she cried over me, and called me a poor lost lamb, and she called me a lot of other names, too, but she never meant no harm by it. + She put me in them new clothes again, and I couldn't do nothing but sweat and sweat, and feel all cramped up. + Well, then, the old thing commenced again. + The widow rung a bell for supper, and you had to come to time. + When you got to the table you couldn't go right to eating, but you had to wait for the widow to tuck down her head and grumble a little over the victuals, though there warn't really anything the matter with them,—that is, nothing only everything was cooked by itself. + In a barrel of odds and ends it is different; things get mixed up, and the juice kind of swaps around, and the things go better. + After supper she got out her book and learned me about Moses and the Bulrushers, and I was in a sweat to find out all about him; but by and by she let it out that Moses had been dead a considerable long time; so then I didn't care no more about him, because I don't take no stock in dead people. + Pretty soon I wanted to smoke, and asked the widow to let me. + But she wouldn't. + She said it was a mean practice and wasn't clean, and I must try to not do it any more. + That is just the way with some people. + They get down on a thing when they don't know nothing about it. + Here she was a-bothering about Moses, which was no kin to her, and no use to anybody, being gone, you see, yet finding a power of fault with me for doing a thing that had some good in it. + And she took snuff, too; of course that was all right, because she done it herself. + Her sister, Miss Watson, a tolerable slim old maid, with goggles on, had just come to live with her, and took a set at me now with a spelling-book. + She worked me middling hard for about an hour, and then the widow made her ease up. + I couldn't stood it much longer. + Then for an hour it was deadly dull, and I was fidgety. + Miss Watson would say, "Don't put your feet up there, Huckleberry;" and "Don't scrunch up like that, Huckleberry—set up straight;" and pretty soon she would say, "Don't gap and stretch like that, Huckleberry—why don't you try to behave?" + Then she told me all about the bad place, and I said I wished I was there. + She got mad then, but I didn't mean no harm. + All I wanted was to go somewheres; all I wanted was a change, I warn't particular. + She said it was wicked to say what I said; said she wouldn't say it for the whole world; she was going to live so as to go to the good place. + Well, I couldn't see no advantage in going where she was going, so I made up my mind I wouldn't try for it. + But I never said so, because it would only make trouble, and wouldn't do no good. + Now she had got a start, and she went on and told me all about the good place. + She said all a body would have to do there was to go around all day long with a harp and sing, forever and ever. + So I didn't think much of it. + But I never said so. + I asked her if she reckoned Tom Sawyer would go there, and she said not by a considerable sight. + I was glad about that, because I wanted him and me to be together. + Miss Watson she kept pecking at me, and it got tiresome and lonesome. + By and by they fetched the niggers in and had prayers, and then everybody was off to bed. + I went up to my room with a piece of candle, and put it on the table. + Then I set down in a chair by the window and tried to think of something cheerful, but it warn't no use. + I felt so lonesome I most wished I was dead. + The stars were shining, and the leaves rustled in the woods ever so mournful; and I heard an owl, away off, who-whooing about somebody that was dead, and a whippowill and a dog crying about somebody that was going to die; and the wind was trying to whisper something to me, and I couldn't make out what it was, and so it made the cold shivers run over me. + Then away out in the woods I heard that kind of a sound that a ghost makes when it wants to tell about something that's on its mind and can't make itself understood, and so can't rest easy in its grave, and has to go about that way every night grieving. + I got so down-hearted and scared I did wish I had some company. + Pretty soon a spider went crawling up my shoulder, and I flipped it off and it lit in the candle; and before I could budge it was all shriveled up. + I didn't need anybody to tell me that that was an awful bad sign and would fetch me some bad luck, so I was scared and most shook the clothes off of me. + I got up and turned around in my tracks three times and crossed my breast every time; and then I tied up a little lock of my hair with a thread to keep witches away. + But I hadn't no confidence. + You do that when you've lost a horseshoe that you've found, instead of nailing it up over the door, but I hadn't ever heard anybody say it was any way to keep off bad luck when you'd killed a spider. + I set down again, a-shaking all over, and got out my pipe for a smoke; for the house was all as still as death now, and so the widow wouldn't know. + Well, after a long time I heard the clock away off in the town go boom—boom—boom—twelve licks; and all still again—stiller than ever. + Pretty soon I heard a twig snap down in the dark amongst the trees—something was a stirring. + I set still and listened. + Directly I could just barely hear a "me-yow! me-yow!" down there. + That was good! + Says I, "me-yow! me-yow!" as soft as I could, and then I put out the light and scrambled out of the window on to the shed. + Then I slipped down to the ground and crawled in among the trees, and, sure enough, there was Tom Sawyer waiting for me. + Chapter II + WE went tiptoeing along a path amongst the trees back towards the end of the widow's garden, stooping down so as the branches wouldn't scrape our heads. + When we was passing by the kitchen I fell over a root and made a noise. + We scrouched down and laid still. + Miss Watson's big nigger, named Jim, was setting in the kitchen door; we could see him pretty clear, because there was a light behind him. + He got up and stretched his neck out about a minute, listening. + Then he says: "Who dah?" + He listened some more; then he come tiptoeing down and stood right between us; we could a touched him, nearly. + Well, likely it was minutes and minutes that there warn't a sound, and we all there so close together. + There was a place on my ankle that got to itching, but I dasn't scratch it; and then my ear begun to itch; and next my back, right between my shoulders. + Seemed like I'd die if I couldn't scratch. + Well, I've noticed that thing plenty times since. + If you are with the quality, or at a funeral, or trying to go to sleep when you ain't sleepy—if you are anywheres where it won't do for you to scratch, why you will itch all over in upwards of a thousand places. + Pretty soon Jim says: + "Say, who is you? + Whar is you? + Dog my cats ef I didn' hear sumf'n. + Well, I know what I's gwyne to do: I's gwyne to set down here and listen tell I hears it agin." + So he set down on the ground betwixt me and Tom. + He leaned his back up against a tree, and stretched his legs out till one of them most touched one of mine. + My nose begun to itch. + It itched till the tears come into my eyes. + But I dasn't scratch. + Then it begun to itch on the inside. + Next I got to itching underneath. + I didn't know how I was going to set still. + This miserableness went on as much as six or seven minutes; but it seemed a sight longer than that. + I was itching in eleven different places now. + I reckoned I couldn't stand it more'n a minute longer, but I set my teeth hard and got ready to try. + Just then Jim begun to breathe heavy; next he begun to snore—and then I was pretty soon comfortable again. + Tom he made a sign to me—kind of a little noise with his mouth—and we went creeping away on our hands and knees. + When we was ten foot off Tom whispered to me, and wanted to tie Jim to the tree for fun. + But I said no; he might wake and make a disturbance, and then they'd find out I warn't in. + Then Tom said he hadn't got candles enough, and he would slip in the kitchen and get some more. + I didn't want him to try. + I said Jim might wake up and come. + But Tom wanted to resk it; so we slid in there and got three candles, and Tom laid five cents on the table for pay. + Then we got out, and I was in a sweat to get away; but nothing would do Tom but he must crawl to where Jim was, on his hands and knees, and play something on him. + I waited, and it seemed a good while, everything was so still and lonesome. + As soon as Tom was back we cut along the path, around the garden fence, and by and by fetched up on the steep top of the hill the other side of the house. + Tom said he slipped Jim's hat off of his head and hung it on a limb right over him, and Jim stirred a little, but he didn't wake. + Afterwards Jim said the witches be witched him and put him in a trance, and rode him all over the State, and then set him under the trees again, and hung his hat on a limb to show who done it. + And next time Jim told it he said they rode him down to New Orleans; and, after that, every time he told it he spread it more and more, till by and by he said they rode him all over the world, and tired him most to death, and his back was all over saddle-boils. + Jim was monstrous proud about it, and he got so he wouldn't hardly notice the other niggers. + Niggers would come miles to hear Jim tell about it, and he was more looked up to than any nigger in that country. + Strange niggers would stand with their mouths open and look him all over, same as if he was a wonder. + Niggers is always talking about witches in the dark by the kitchen fire; but whenever one was talking and letting on to know all about such things, Jim would happen in and say, "Hm! + What you know 'bout witches?" + and that nigger was corked up and had to take a back seat. + Jim always kept that five-center piece round his neck with a string, and said it was a charm the devil give to him with his own hands, and told him he could cure anybody with it and fetch witches whenever he wanted to just by saying something to it; but he never told what it was he said to it. + Niggers would come from all around there and give Jim anything they had, just for a sight of that five-center piece; but they wouldn't touch it, because the devil had had his hands on it. + Jim was most ruined for a servant, because he got stuck up on account of having seen the devil and been rode by witches. + Well, when Tom and me got to the edge of the hilltop we looked away down into the village and could see three or four lights twinkling, where there was sick folks, maybe; and the stars over us was sparkling ever so fine; and down by the village was the river, a whole mile broad, and awful still and grand. + We went down the hill and found Jo Harper and Ben Rogers, and two or three more of the boys, hid in the old tanyard. + So we unhitched a skiff and pulled down the river two mile and a half, to the big scar on the hillside, and went ashore. + We went to a clump of bushes, and Tom made everybody swear to keep the secret, and then showed them a hole in the hill, right in the thickest part of the bushes. + Then we lit the candles, and crawled in on our hands and knees. + We went about two hundred yards, and then the cave opened up. + Tom poked about amongst the passages, and pretty soon ducked under a wall where you wouldn't a noticed that there was a hole. + We went along a narrow place and got into a kind of room, all damp and sweaty and cold, and there we stopped. + Tom says: + "Now, we'll start this band of robbers and call it Tom Sawyer's Gang. + Everybody that wants to join has got to take an oath, and write his name in blood." + Everybody was willing. + So Tom got out a sheet of paper that he had wrote the oath on, and read it. + It swore every boy to stick to the band, and never tell any of the secrets; and if anybody done anything to any boy in the band, whichever boy was ordered to kill that person and his family must do it, and he mustn't eat and he mustn't sleep till he had killed them and hacked a cross in their breasts, which was the sign of the band. + And nobody that didn't belong to the band could use that mark, and if he did he must be sued; and if he done it again he must be killed. + And if anybody that belonged to the band told the secrets, he must have his throat cut, and then have his carcass burnt up and the ashes scattered all around, and his name blotted off of the list with blood and never mentioned again by the gang, but have a curse put on it and be forgot forever. + Everybody said it was a real beautiful oath, and asked Tom if he got it out of his own head. + He said, some of it, but the rest was out of pirate-books and robber-books, and every gang that was high-toned had it. + Some thought it would be good to kill the _families_ of boys that told the secrets. + Tom said it was a good idea, so he took a pencil and wrote it in. + Then Ben Rogers says: + "Here's Huck Finn, he hain't got no family; what you going to do 'bout him?" + "Well, hain't he got a father?" + says Tom Sawyer. + "Yes, he's got a father, but you can't never find him these days. + He used to lay drunk with the hogs in the tanyard, but he hain't been seen in these parts for a year or more." + They talked it over, and they was going to rule me out, because they said every boy must have a family or somebody to kill, or else it wouldn't be fair and square for the others. + Well, nobody could think of anything to do—everybody was stumped, and set still. + I was most ready to cry; but all at once I thought of a way, and so I offered them Miss Watson—they could kill her. + Everybody said: + "Oh, she'll do. + That's all right. + Huck can come in." + Then they all stuck a pin in their fingers to get blood to sign with, and I made my mark on the paper. + "Now," says Ben Rogers, "what's the line of business of this Gang?" + "Nothing only robbery and murder," Tom said. + "But who are we going to rob? + —houses, or cattle, or—" + "Stuff! + stealing cattle and such things ain't robbery; it's burglary," says Tom Sawyer. + "We ain't burglars. + That ain't no sort of style. + We are highwaymen. + We stop stages and carriages on the road, with masks on, and kill the people and take their watches and money." + "Must we always kill the people?" + "Oh, certainly. + It's best. + Some authorities think different, but mostly it's considered best to kill them—except some that you bring to the cave here, and keep them till they're ransomed." + "Ransomed? + What's that?" + "I don't know. + But that's what they do. + I've seen it in books; and so of course that's what we've got to do." + "But how can we do it if we don't know what it is?" + "Why, blame it all, we've _got_ to do it. + Don't I tell you it's in the books? + Do you want to go to doing different from what's in the books, and get things all muddled up?" + "Oh, that's all very fine to _say_, Tom Sawyer, but how in the nation are these fellows going to be ransomed if we don't know how to do it to them? + —that's the thing I want to get at. + Now, what do you reckon it is?" + "Well, I don't know. + But per'aps if we keep them till they're ransomed, it means that we keep them till they're dead." + "Now, that's something _like_. + That'll answer. + Why couldn't you said that before? + We'll keep them till they're ransomed to death; and a bothersome lot they'll be, too—eating up everything, and always trying to get loose." + "How you talk, Ben Rogers. + How can they get loose when there's a guard over them, ready to shoot them down if they move a peg?" + "A guard! + Well, that _is_ good. + So somebody's got to set up all night and never get any sleep, just so as to watch them. + I think that's foolishness. + Why can't a body take a club and ransom them as soon as they get here?" + "Because it ain't in the books so—that's why. + Now, Ben Rogers, do you want to do things regular, or don't you? + —that's the idea. + Don't you reckon that the people that made the books knows what's the correct thing to do? + Do you reckon _you_ can learn 'em anything? + Not by a good deal. + No, sir, we'll just go on and ransom them in the regular way." + "All right. + I don't mind; but I say it's a fool way, anyhow. + Say, do we kill the women, too?" + "Well, Ben Rogers, if I was as ignorant as you I wouldn't let on. + Kill the women? + No; nobody ever saw anything in the books like that. + You fetch them to the cave, and you're always as polite as pie to them; and by and by they fall in love with you, and never want to go home any more." + "Well, if that's the way I'm agreed, but I don't take no stock in it. + Mighty soon we'll have the cave so cluttered up with women, and fellows waiting to be ransomed, that there won't be no place for the robbers. + But go ahead, I ain't got nothing to say." + Little Tommy Barnes was asleep now, and when they waked him up he was scared, and cried, and said he wanted to go home to his ma, and didn't want to be a robber any more. + So they all made fun of him, and called him cry-baby, and that made him mad, and he said he would go straight and tell all the secrets. + But Tom give him five cents to keep quiet, and said we would all go home and meet next week, and rob somebody and kill some people. + Ben Rogers said he couldn't get out much, only Sundays, and so he wanted to begin next Sunday; but all the boys said it would be wicked to do it on Sunday, and that settled the thing. + They agreed to get together and fix a day as soon as they could, and then we elected Tom Sawyer first captain and Jo Harper second captain of the Gang, and so started home. + I clumb up the shed and crept into my window just before day was breaking. + My new clothes was all greased up and clayey, and I was dog-tired. + CHAPTER III. + WELL, I got a good going-over in the morning from old Miss Watson on account of my clothes; but the widow she didn't scold, but only cleaned off the grease and clay, and looked so sorry that I thought I would behave awhile if I could. + Then Miss Watson she took me in the closet and prayed, but nothing come of it. + She told me to pray every day, and whatever I asked for I would get it. + But it warn't so. + I tried it. + Once I got a fish-line, but no hooks. + It warn't any good to me without hooks. + I tried for the hooks three or four times, but somehow I couldn't make it work. + By and by, one day, I asked Miss Watson to try for me, but she said I was a fool. + She never told me why, and I couldn't make it out no way. + I set down one time back in the woods, and had a long think about it. + I says to myself, if a body can get anything they pray for, why don't Deacon Winn get back the money he lost on pork? + Why can't the widow get back her silver snuffbox that was stole? + Why can't Miss Watson fat up? + No, says I to my self, there ain't nothing in it. + I went and told the widow about it, and she said the thing a body could get by praying for it was "spiritual gifts." + This was too many for me, but she told me what she meant—I must help other people, and do everything I could for other people, and look out for them all the time, and never think about myself. + This was including Miss Watson, as I took it. + I went out in the woods and turned it over in my mind a long time, but I couldn't see no advantage about it—except for the other people; so at last I reckoned I wouldn't worry about it any more, but just let it go. + Sometimes the widow would take me one side and talk about Providence in a way to make a body's mouth water; but maybe next day Miss Watson would take hold and knock it all down again. + I judged I could see that there was two Providences, and a poor chap would stand considerable show with the widow's Providence, but if Miss Watson's got him there warn't no help for him any more. + I thought it all out, and reckoned I would belong to the widow's if he wanted me, though I couldn't make out how he was a-going to be any better off then than what he was before, seeing I was so ignorant, and so kind of low-down and ornery. + Pap he hadn't been seen for more than a year, and that was comfortable for me; I didn't want to see him no more. + He used to always whale me when he was sober and could get his hands on me; though I used to take to the woods most of the time when he was around. + Well, about this time he was found in the river drownded, about twelve mile above town, so people said. + They judged it was him, anyway; said this drownded man was just his size, and was ragged, and had uncommon long hair, which was all like pap; but they couldn't make nothing out of the face, because it had been in the water so long it warn't much like a face at all. + They said he was floating on his back in the water. + They took him and buried him on the bank. + But I warn't comfortable long, because I happened to think of something. + I knowed mighty well that a drownded man don't float on his back, but on his face. + So I knowed, then, that this warn't pap, but a woman dressed up in a man's clothes. + So I was uncomfortable again. + I judged the old man would turn up again by and by, though I wished he wouldn't. + We played robber now and then about a month, and then I resigned. + All the boys did. + We hadn't robbed nobody, hadn't killed any people, but only just pretended. + We used to hop out of the woods and go charging down on hog-drivers and women in carts taking garden stuff to market, but we never hived any of them. + Tom Sawyer called the hogs "ingots," and he called the turnips and stuff "julery," and we would go to the cave and powwow over what we had done, and how many people we had killed and marked. + But I couldn't see no profit in it. + One time Tom sent a boy to run about town with a blazing stick, which he called a slogan (which was the sign for the Gang to get together), and then he said he had got secret news by his spies that next day a whole parcel of Spanish merchants and rich A-rabs was going to camp in Cave Hollow with two hundred elephants, and six hundred camels, and over a thousand "sumter" mules, all loaded down with di'monds, and they didn't have only a guard of four hundred soldiers, and so we would lay in ambuscade, as he called it, and kill the lot and scoop the things. + He said we must slick up our swords and guns, and get ready. + He never could go after even a turnip-cart but he must have the swords and guns all scoured up for it, though they was only lath and broomsticks, and you might scour at them till you rotted, and then they warn't worth a mouthful of ashes more than what they was before. + I didn't believe we could lick such a crowd of Spaniards and A-rabs, but I wanted to see the camels and elephants, so I was on hand next day, Saturday, in the ambuscade; and when we got the word we rushed out of the woods and down the hill. + But there warn't no Spaniards and A-rabs, and there warn't no camels nor no elephants. + It warn't anything but a Sunday-school picnic, and only a primer-class at that. + We busted it up, and chased the children up the hollow; but we never got anything but some doughnuts and jam, though Ben Rogers got a rag doll, and Jo Harper got a hymn-book and a tract; and then the teacher charged in, and made us drop everything and cut. + I didn't see no di'monds, and I told Tom Sawyer so. + He said there was loads of them there, anyway; and he said there was A-rabs there, too, and elephants and things. + I said, why couldn't we see them, then? + He said if I warn't so ignorant, but had read a book called Don Quixote, I would know without asking. + He said it was all done by enchantment. + He said there was hundreds of soldiers there, and elephants and treasure, and so on, but we had enemies which he called magicians; and they had turned the whole thing into an infant Sunday-school, just out of spite. + I said, all right; then the thing for us to do was to go for the magicians. + Tom Sawyer said I was a numskull. + "Why," said he, "a magician could call up a lot of genies, and they would hash you up like nothing before you could say Jack Robinson. + They are as tall as a tree and as big around as a church." + "Well," I says, "s'pose we got some genies to help _us_—can't we lick the other crowd then?" + "How you going to get them?" + "I don't know. + How do _they_ get them?" + "Why, they rub an old tin lamp or an iron ring, and then the genies come tearing in, with the thunder and lightning a-ripping around and the smoke a-rolling, and everything they're told to do they up and do it. + They don't think nothing of pulling a shot-tower up by the roots, and belting a Sunday-school superintendent over the head with it—or any other man." + "Who makes them tear around so?" + "Why, whoever rubs the lamp or the ring. + They belong to whoever rubs the lamp or the ring, and they've got to do whatever he says. + If he tells them to build a palace forty miles long out of di'monds, and fill it full of chewing-gum, or whatever you want, and fetch an emperor's daughter from China for you to marry, they've got to do it—and they've got to do it before sun-up next morning, too. + And more: they've got to waltz that palace around over the country wherever you want it, you understand." + "Well," says I, "I think they are a pack of flat-heads for not keeping the palace themselves 'stead of fooling them away like that. + And what's more—if I was one of them I would see a man in Jericho before I would drop my business and come to him for the rubbing of an old tin lamp." + "How you talk, Huck Finn. + Why, you'd _have_ to come when he rubbed it, whether you wanted to or not." + "What! + and I as high as a tree and as big as a church? + All right, then; I _would_ come; but I lay I'd make that man climb the highest tree there was in the country." + "Shucks, it ain't no use to talk to you, Huck Finn. + You don't seem to know anything, somehow—perfect saphead." + I thought all this over for two or three days, and then I reckoned I would see if there was anything in it. + I got an old tin lamp and an iron ring, and went out in the woods and rubbed and rubbed till I sweat like an Injun, calculating to build a palace and sell it; but it warn't no use, none of the genies come. + So then I judged that all that stuff was only just one of Tom Sawyer's lies. + I reckoned he believed in the A-rabs and the elephants, but as for me I think different. + It had all the marks of a Sunday-school. + CHAPTER IV. + WELL, three or four months run along, and it was well into the winter now. + I had been to school most all the time and could spell and read and write just a little, and could say the multiplication table up to six times seven is thirty-five, and I don't reckon I could ever get any further than that if I was to live forever. + I don't take no stock in mathematics, anyway. + At first I hated the school, but by and by I got so I could stand it. + Whenever I got uncommon tired I played hookey, and the hiding I got next day done me good and cheered me up. + So the longer I went to school the easier it got to be. + I was getting sort of used to the widow's ways, too, and they warn't so raspy on me. + Living in a house and sleeping in a bed pulled on me pretty tight mostly, but before the cold weather I used to slide out and sleep in the woods sometimes, and so that was a rest to me. + I liked the old ways best, but I was getting so I liked the new ones, too, a little bit. + The widow said I was coming along slow but sure, and doing very satisfactory. + She said she warn't ashamed of me. + One morning I happened to turn over the salt-cellar at breakfast. + I reached for some of it as quick as I could to throw over my left shoulder and keep off the bad luck, but Miss Watson was in ahead of me, and crossed me off. + She says, "Take your hands away, Huckleberry; what a mess you are always making!" + The widow put in a good word for me, but that warn't going to keep off the bad luck, I knowed that well enough. + I started out, after breakfast, feeling worried and shaky, and wondering where it was going to fall on me, and what it was going to be. + There is ways to keep off some kinds of bad luck, but this wasn't one of them kind; so I never tried to do anything, but just poked along low-spirited and on the watch-out. + I went down to the front garden and clumb over the stile where you go through the high board fence. + There was an inch of new snow on the ground, and I seen somebody's tracks. + They had come up from the quarry and stood around the stile a while, and then went on around the garden fence. + It was funny they hadn't come in, after standing around so. + I couldn't make it out. + It was very curious, somehow. + I was going to follow around, but I stooped down to look at the tracks first. + I didn't notice anything at first, but next I did. + There was a cross in the left boot-heel made with big nails, to keep off the devil. + I was up in a second and shinning down the hill. + I looked over my shoulder every now and then, but I didn't see nobody. + I was at Judge Thatcher's as quick as I could get there. + He said: + "Why, my boy, you are all out of breath. + Did you come for your interest?" + "No, sir," I says; "is there some for me?" + "Oh, yes, a half-yearly is in last night—over a hundred and fifty dollars. + Quite a fortune for you. + You had better let me invest it along with your six thousand, because if you take it you'll spend it." + "No, sir," I says, "I don't want to spend it. + I don't want it at all—nor the six thousand, nuther. + I want you to take it; I want to give it to you—the six thousand and all." + He looked surprised. + He couldn't seem to make it out. + He says: + "Why, what can you mean, my boy?" + I says, "Don't you ask me no questions about it, please. + You'll take it—won't you?" + He says: + "Well, I'm puzzled. + Is something the matter?" + "Please take it," says I, "and don't ask me nothing—then I won't have to tell no lies." + He studied a while, and then he says: + "Oho-o! + I think I see. + You want to _sell_ all your property to me—not give it. + That's the correct idea." + Then he wrote something on a paper and read it over, and says: + "There; you see it says 'for a consideration.' + That means I have bought it of you and paid you for it. + Here's a dollar for you. + Now you sign it." + So I signed it, and left. + Miss Watson's nigger, Jim, had a hair-ball as big as your fist, which had been took out of the fourth stomach of an ox, and he used to do magic with it. + He said there was a spirit inside of it, and it knowed everything. + So I went to him that night and told him pap was here again, for I found his tracks in the snow. + What I wanted to know was, what he was going to do, and was he going to stay? + Jim got out his hair-ball and said something over it, and then he held it up and dropped it on the floor. + It fell pretty solid, and only rolled about an inch. + Jim tried it again, and then another time, and it acted just the same. + Jim got down on his knees, and put his ear against it and listened. + But it warn't no use; he said it wouldn't talk. + He said sometimes it wouldn't talk without money. + I told him I had an old slick counterfeit quarter that warn't no good because the brass showed through the silver a little, and it wouldn't pass nohow, even if the brass didn't show, because it was so slick it felt greasy, and so that would tell on it every time. + (I reckoned I wouldn't say nothing about the dollar I got from the judge.) + I said it was pretty bad money, but maybe the hair-ball would take it, because maybe it wouldn't know the difference. + Jim smelt it and bit it and rubbed it, and said he would manage so the hair-ball would think it was good. + He said he would split open a raw Irish potato and stick the quarter in between and keep it there all night, and next morning you couldn't see no brass, and it wouldn't feel greasy no more, and so anybody in town would take it in a minute, let alone a hair-ball. + Well, I knowed a potato would do that before, but I had forgot it. + Jim put the quarter under the hair-ball, and got down and listened again. + This time he said the hair-ball was all right. + He said it would tell my whole fortune if I wanted it to. + I says, go on. + So the hair-ball talked to Jim, and Jim told it to me. + He says: + "Yo' ole father doan' know yit what he's a-gwyne to do. + Sometimes he spec he'll go 'way, en den agin he spec he'll stay. + De bes' way is to res' easy en let de ole man take his own way. + Dey's two angels hoverin' roun' 'bout him. + One uv 'em is white en shiny, en t'other one is black. + De white one gits him to go right a little while, den de black one sail in en bust it all up. + A body can't tell yit which one gwyne to fetch him at de las'. + But you is all right. + You gwyne to have considable trouble in yo' life, en considable joy. + Sometimes you gwyne to git hurt, en sometimes you gwyne to git sick; but every time you's gwyne to git well agin. + Dey's two gals flyin' 'bout you in yo' life. + One uv 'em's light en t'other one is dark. + One is rich en t'other is po'. + You's gwyne to marry de po' one fust en de rich one by en by. + You wants to keep 'way fum de water as much as you kin, en don't run no resk, 'kase it's down in de bills dat you's gwyne to git hung." + When I lit my candle and went up to my room that night there sat pap his own self! + CHAPTER V. + I had shut the door to. + Then I turned around and there he was. + I used to be scared of him all the time, he tanned me so much. + I reckoned I was scared now, too; but in a minute I see I was mistaken—that is, after the first jolt, as you may say, when my breath sort of hitched, he being so unexpected; but right away after I see I warn't scared of him worth bothring about. + He was most fifty, and he looked it. + His hair was long and tangled and greasy, and hung down, and you could see his eyes shining through like he was behind vines. + It was all black, no gray; so was his long, mixed-up whiskers. + There warn't no color in his face, where his face showed; it was white; not like another man's white, but a white to make a body sick, a white to make a body's flesh crawl—a tree-toad white, a fish-belly white. + As for his clothes—just rags, that was all. + He had one ankle resting on t'other knee; the boot on that foot was busted, and two of his toes stuck through, and he worked them now and then. + His hat was laying on the floor—an old black slouch with the top caved in, like a lid. + I stood a-looking at him; he set there a-looking at me, with his chair tilted back a little. + I set the candle down. + I noticed the window was up; so he had clumb in by the shed. + He kept a-looking me all over. + By and by he says: "Starchy clothes—very. + You think you're a good deal of a big-bug, _don't_ you?" + "Maybe I am, maybe I ain't," I says. + "Don't you give me none o' your lip," says he. + "You've put on considerable many frills since I been away. + I'll take you down a peg before I get done with you. + You're educated, too, they say—can read and write. + You think you're better'n your father, now, don't you, because he can't? + _I'll_ take it out of you. + Who told you you might meddle with such hifalut'n foolishness, hey? + —who told you you could?" + "The widow. + She told me." + "The widow, hey? + —and who told the widow she could put in her shovel about a thing that ain't none of her business?" + "Nobody never told her." + "Well, I'll learn her how to meddle. + And looky here—you drop that school, you hear? + I'll learn people to bring up a boy to put on airs over his own father and let on to be better'n what _he_ is. + You lemme catch you fooling around that school again, you hear? + Your mother couldn't read, and she couldn't write, nuther, before she died. + None of the family couldn't before _they_ died. + I can't; and here you're a-swelling yourself up like this. + I ain't the man to stand it—you hear? + Say, lemme hear you read." + I took up a book and begun something about General Washington and the wars. + When I'd read about a half a minute, he fetched the book a whack with his hand and knocked it across the house. + He says: "It's so. + You can do it. + I had my doubts when you told me. + Now looky here; you stop that putting on frills. + I won't have it. + I'll lay for you, my smarty; and if I catch you about that school I'll tan you good. + First you know you'll get religion, too. + I never see such a son." + He took up a little blue and yaller picture of some cows and a boy, and says: "What's this?" + "It's something they give me for learning my lessons good." + He tore it up, and says: "I'll give you something better—I'll give you a cowhide." + He set there a-mumbling and a-growling a minute, and then he says: "_Ain't_ you a sweet-scented dandy, though? + A bed; and bedclothes; and a look'n'-glass; and a piece of carpet on the floor—and your own father got to sleep with the hogs in the tanyard. + I never see such a son. + I bet I'll take some o' these frills out o' you before I'm done with you. + Why, there ain't no end to your airs—they say you're rich. + Hey? + —how's that?" + "They lie—that's how." + "Looky here—mind how you talk to me; I'm a-standing about all I can stand now—so don't gimme no sass. + I've been in town two days, and I hain't heard nothing but about you bein' rich. + I heard about it away down the river, too. + That's why I come. + You git me that money to-morrow—I want it." + "I hain't got no money." + "It's a lie. + Judge Thatcher's got it. + You git it. + I want it." + "I hain't got no money, I tell you. + You ask Judge Thatcher; he'll tell you the same." + "All right. + I'll ask him; and I'll make him pungle, too, or I'll know the reason why. + Say, how much you got in your pocket? + I want it." + "I hain't got only a dollar, and I want that to—" "It don't make no difference what you want it for—you just shell it out." + He took it and bit it to see if it was good, and then he said he was going down town to get some whisky; said he hadn't had a drink all day. + When he had got out on the shed he put his head in again, and cussed me for putting on frills and trying to be better than him; and when I reckoned he was gone he come back and put his head in again, and told me to mind about that school, because he was going to lay for me and lick me if I didn't drop that. + Next day he was drunk, and he went to Judge Thatcher's and bullyragged him, and tried to make him give up the money; but he couldn't, and then he swore he'd make the law force him. + The judge and the widow went to law to get the court to take me away from him and let one of them be my guardian; but it was a new judge that had just come, and he didn't know the old man; so he said courts mustn't interfere and separate families if they could help it; said he'd druther not take a child away from its father. + So Judge Thatcher and the widow had to quit on the business. + That pleased the old man till he couldn't rest. + He said he'd cowhide me till I was black and blue if I didn't raise some money for him. + I borrowed three dollars from Judge Thatcher, and pap took it and got drunk, and went a-blowing around and cussing and whooping and carrying on; and he kept it up all over town, with a tin pan, till most midnight; then they jailed him, and next day they had him before court, and jailed him again for a week. + But he said _he_ was satisfied; said he was boss of his son, and he'd make it warm for _him_. + When he got out the new judge said he was a-going to make a man of him. + So he took him to his own house, and dressed him up clean and nice, and had him to breakfast and dinner and supper with the family, and was just old pie to him, so to speak. + And after supper he talked to him about temperance and such things till the old man cried, and said he'd been a fool, and fooled away his life; but now he was a-going to turn over a new leaf and be a man nobody wouldn't be ashamed of, and he hoped the judge would help him and not look down on him. + The judge said he could hug him for them words; so he cried, and his wife she cried again; pap said he'd been a man that had always been misunderstood before, and the judge said he believed it. + The old man said that what a man wanted that was down was sympathy, and the judge said it was so; so they cried again. + And when it was bedtime the old man rose up and held out his hand, and says: "Look at it, gentlemen and ladies all; take a-hold of it; shake it. + There's a hand that was the hand of a hog; but it ain't so no more; it's the hand of a man that's started in on a new life, and'll die before he'll go back. + You mark them words—don't forget I said them. + It's a clean hand now; shake it—don't be afeard." + So they shook it, one after the other, all around, and cried. + The judge's wife she kissed it. + Then the old man he signed a pledge—made his mark. + The judge said it was the holiest time on record, or something like that. + Then they tucked the old man into a beautiful room, which was the spare room, and in the night some time he got powerful thirsty and clumb out on to the porch-roof and slid down a stanchion and traded his new coat for a jug of forty-rod, and clumb back again and had a good old time; and towards daylight he crawled out again, drunk as a fiddler, and rolled off the porch and broke his left arm in two places, and was most froze to death when somebody found him after sun-up. + And when they come to look at that spare room they had to take soundings before they could navigate it. + The judge he felt kind of sore. + He said he reckoned a body could reform the old man with a shotgun, maybe, but he didn't know no other way. + CHAPTER VI. + WELL, pretty soon the old man was up and around again, and then he went for Judge Thatcher in the courts to make him give up that money, and he went for me, too, for not stopping school. + He catched me a couple of times and thrashed me, but I went to school just the same, and dodged him or outrun him most of the time. + I didn't want to go to school much before, but I reckoned I'd go now to spite pap. + That law trial was a slow business—appeared like they warn't ever going to get started on it; so every now and then I'd borrow two or three dollars off of the judge for him, to keep from getting a cowhiding. + Every time he got money he got drunk; and every time he got drunk he raised Cain around town; and every time he raised Cain he got jailed. + He was just suited—this kind of thing was right in his line. + He got to hanging around the widow's too much and so she told him at last that if he didn't quit using around there she would make trouble for him. + Well, _wasn't_ he mad? + He said he would show who was Huck Finn's boss. + So he watched out for me one day in the spring, and catched me, and took me up the river about three mile in a skiff, and crossed over to the Illinois shore where it was woody and there warn't no houses but an old log hut in a place where the timber was so thick you couldn't find it if you didn't know where it was. + He kept me with him all the time, and I never got a chance to run off. + We lived in that old cabin, and he always locked the door and put the key under his head nights. + He had a gun which he had stole, I reckon, and we fished and hunted, and that was what we lived on. + Every little while he locked me in and went down to the store, three miles, to the ferry, and traded fish and game for whisky, and fetched it home and got drunk and had a good time, and licked me. + The widow she found out where I was by and by, and she sent a man over to try to get hold of me; but pap drove him off with the gun, and it warn't long after that till I was used to being where I was, and liked it—all but the cowhide part. + It was kind of lazy and jolly, laying off comfortable all day, smoking and fishing, and no books nor study. + Two months or more run along, and my clothes got to be all rags and dirt, and I didn't see how I'd ever got to like it so well at the widow's, where you had to wash, and eat on a plate, and comb up, and go to bed and get up regular, and be forever bothering over a book, and have old Miss Watson pecking at you all the time. + I didn't want to go back no more. + I had stopped cussing, because the widow didn't like it; but now I took to it again because pap hadn't no objections. + It was pretty good times up in the woods there, take it all around. + But by and by pap got too handy with his hick'ry, and I couldn't stand it. + I was all over welts. + He got to going away so much, too, and locking me in. + Once he locked me in and was gone three days. + It was dreadful lonesome. + I judged he had got drownded, and I wasn't ever going to get out any more. + I was scared. + I made up my mind I would fix up some way to leave there. + I had tried to get out of that cabin many a time, but I couldn't find no way. + There warn't a window to it big enough for a dog to get through. + I couldn't get up the chimbly; it was too narrow. + The door was thick, solid oak slabs. + Pap was pretty careful not to leave a knife or anything in the cabin when he was away; I reckon I had hunted the place over as much as a hundred times; well, I was most all the time at it, because it was about the only way to put in the time. + But this time I found something at last; I found an old rusty wood-saw without any handle; it was laid in between a rafter and the clapboards of the roof. + I greased it up and went to work. + There was an old horse-blanket nailed against the logs at the far end of the cabin behind the table, to keep the wind from blowing through the chinks and putting the candle out. + I got under the table and raised the blanket, and went to work to saw a section of the big bottom log out—big enough to let me through. + Well, it was a good long job, but I was getting towards the end of it when I heard pap's gun in the woods. + I got rid of the signs of my work, and dropped the blanket and hid my saw, and pretty soon pap come in. + Pap warn't in a good humor—so he was his natural self. + He said he was down town, and everything was going wrong. + His lawyer said he reckoned he would win his lawsuit and get the money if they ever got started on the trial; but then there was ways to put it off a long time, and Judge Thatcher knowed how to do it. + And he said people allowed there'd be another trial to get me away from him and give me to the widow for my guardian, and they guessed it would win this time. + This shook me up considerable, because I didn't want to go back to the widow's any more and be so cramped up and sivilized, as they called it. + Then the old man got to cussing, and cussed everything and everybody he could think of, and then cussed them all over again to make sure he hadn't skipped any, and after that he polished off with a kind of a general cuss all round, including a considerable parcel of people which he didn't know the names of, and so called them what's-his-name when he got to them, and went right along with his cussing. + He said he would like to see the widow get me. + He said he would watch out, and if they tried to come any such game on him he knowed of a place six or seven mile off to stow me in, where they might hunt till they dropped and they couldn't find me. + That made me pretty uneasy again, but only for a minute; I reckoned I wouldn't stay on hand till he got that chance. + The old man made me go to the skiff and fetch the things he had got. + There was a fifty-pound sack of corn meal, and a side of bacon, ammunition, and a four-gallon jug of whisky, and an old book and two newspapers for wadding, besides some tow. + I toted up a load, and went back and set down on the bow of the skiff to rest. + I thought it all over, and I reckoned I would walk off with the gun and some lines, and take to the woods when I run away. + I guessed I wouldn't stay in one place, but just tramp right across the country, mostly night times, and hunt and fish to keep alive, and so get so far away that the old man nor the widow couldn't ever find me any more. + I judged I would saw out and leave that night if pap got drunk enough, and I reckoned he would. + I got so full of it I didn't notice how long I was staying till the old man hollered and asked me whether I was asleep or drownded. + I got the things all up to the cabin, and then it was about dark. + While I was cooking supper the old man took a swig or two and got sort of warmed up, and went to ripping again. + He had been drunk over in town, and laid in the gutter all night, and he was a sight to look at. + A body would a thought he was Adam—he was just all mud. + Whenever his liquor begun to work he most always went for the govment, this time he says: + "Call this a govment! + why, just look at it and see what it's like. + Here's the law a-standing ready to take a man's son away from him—a man's own son, which he has had all the trouble and all the anxiety and all the expense of raising. + Yes, just as that man has got that son raised at last, and ready to go to work and begin to do suthin' for _him_ and give him a rest, the law up and goes for him. + And they call _that_ govment! + That ain't all, nuther. + The law backs that old Judge Thatcher up and helps him to keep me out o' my property. + Here's what the law does: The law takes a man worth six thousand dollars and up'ards, and jams him into an old trap of a cabin like this, and lets him go round in clothes that ain't fitten for a hog. + They call that govment! + A man can't get his rights in a govment like this. + Sometimes I've a mighty notion to just leave the country for good and all. + Yes, and I _told_ 'em so; I told old Thatcher so to his face. + Lots of 'em heard me, and can tell what I said. + Says I, for two cents I'd leave the blamed country and never come a-near it agin. + Them's the very words. + I says look at my hat—if you call it a hat—but the lid raises up and the rest of it goes down till it's below my chin, and then it ain't rightly a hat at all, but more like my head was shoved up through a jint o' stove-pipe. + Look at it, says I—such a hat for me to wear—one of the wealthiest men in this town if I could git my rights. + "Oh, yes, this is a wonderful govment, wonderful. + Why, looky here. + There was a free nigger there from Ohio—a mulatter, most as white as a white man. + He had the whitest shirt on you ever see, too, and the shiniest hat; and there ain't a man in that town that's got as fine clothes as what he had; and he had a gold watch and chain, and a silver-headed cane—the awfulest old gray-headed nabob in the State. + And what do you think? + They said he was a p'fessor in a college, and could talk all kinds of languages, and knowed everything. + And that ain't the wust. + They said he could _vote_ when he was at home. + Well, that let me out. + Thinks I, what is the country a-coming to? + It was 'lection day, and I was just about to go and vote myself if I warn't too drunk to get there; but when they told me there was a State in this country where they'd let that nigger vote, I drawed out. + I says I'll never vote agin. + Them's the very words I said; they all heard me; and the country may rot for all me—I'll never vote agin as long as I live. + And to see the cool way of that nigger—why, he wouldn't a give me the road if I hadn't shoved him out o' the way. + I says to the people, why ain't this nigger put up at auction and sold? + —that's what I want to know. + And what do you reckon they said? + Why, they said he couldn't be sold till he'd been in the State six months, and he hadn't been there that long yet. + There, now—that's a specimen. + They call that a govment that can't sell a free nigger till he's been in the State six months. + Here's a govment that calls itself a govment, and lets on to be a govment, and thinks it is a govment, and yet's got to set stock-still for six whole months before it can take a hold of a prowling, thieving, infernal, white-shirted free nigger, and—" + Pap was agoing on so he never noticed where his old limber legs was taking him to, so he went head over heels over the tub of salt pork and barked both shins, and the rest of his speech was all the hottest kind of language—mostly hove at the nigger and the govment, though he give the tub some, too, all along, here and there. + He hopped around the cabin considerable, first on one leg and then on the other, holding first one shin and then the other one, and at last he let out with his left foot all of a sudden and fetched the tub a rattling kick. + But it warn't good judgment, because that was the boot that had a couple of his toes leaking out of the front end of it; so now he raised a howl that fairly made a body's hair raise, and down he went in the dirt, and rolled there, and held his toes; and the cussing he done then laid over anything he had ever done previous. + He said so his own self afterwards. + He had heard old Sowberry Hagan in his best days, and he said it laid over him, too; but I reckon that was sort of piling it on, maybe. + After supper pap took the jug, and said he had enough whisky there for two drunks and one delirium tremens. + That was always his word. + I judged he would be blind drunk in about an hour, and then I would steal the key, or saw myself out, one or t'other. + He drank and drank, and tumbled down on his blankets by and by; but luck didn't run my way. + He didn't go sound asleep, but was uneasy. + He groaned and moaned and thrashed around this way and that for a long time. + At last I got so sleepy I couldn't keep my eyes open all I could do, and so before I knowed what I was about I was sound asleep, and the candle burning. + I don't know how long I was asleep, but all of a sudden there was an awful scream and I was up. + There was pap looking wild, and skipping around every which way and yelling about snakes. + He said they was crawling up his legs; and then he would give a jump and scream, and say one had bit him on the cheek—but I couldn't see no snakes. + He started and run round and round the cabin, hollering "Take him off! + take him off! + he's biting me on the neck!" + I never see a man look so wild in the eyes. + Pretty soon he was all fagged out, and fell down panting; then he rolled over and over wonderful fast, kicking things every which way, and striking and grabbing at the air with his hands, and screaming and saying there was devils a-hold of him. + He wore out by and by, and laid still a while, moaning. + Then he laid stiller, and didn't make a sound. + I could hear the owls and the wolves away off in the woods, and it seemed terrible still. + He was laying over by the corner. + By and by he raised up part way and listened, with his head to one side. + He says, very low: + "Tramp—tramp—tramp; that's the dead; tramp—tramp—tramp; they're coming after me; but I won't go. + Oh, they're here! + don't touch me—don't! + hands off—they're cold; let go. + Oh, let a poor devil alone!" + Then he went down on all fours and crawled off, begging them to let him alone, and he rolled himself up in his blanket and wallowed in under the old pine table, still a-begging; and then he went to crying. + I could hear him through the blanket. + By and by he rolled out and jumped up on his feet looking wild, and he see me and went for me. + He chased me round and round the place with a clasp-knife, calling me the Angel of Death, and saying he would kill me, and then I couldn't come for him no more. + I begged, and told him I was only Huck; but he laughed _such_ a screechy laugh, and roared and cussed, and kept on chasing me up. + Once when I turned short and dodged under his arm he made a grab and got me by the jacket between my shoulders, and I thought I was gone; but I slid out of the jacket quick as lightning, and saved myself. + Pretty soon he was all tired out, and dropped down with his back against the door, and said he would rest a minute and then kill me. + He put his knife under him, and said he would sleep and get strong, and then he would see who was who. + So he dozed off pretty soon. + By and by I got the old split-bottom chair and clumb up as easy as I could, not to make any noise, and got down the gun. + I slipped the ramrod down it to make sure it was loaded, then I laid it across the turnip barrel, pointing towards pap, and set down behind it to wait for him to stir. + And how slow and still the time did drag along. + CHAPTER VII. + "GIT up! + What you 'bout?" + I opened my eyes and looked around, trying to make out where I was. + It was after sun-up, and I had been sound asleep. + Pap was standing over me looking sour and sick, too. + He says: "What you doin' with this gun?" + I judged he didn't know nothing about what he had been doing, so I says: "Somebody tried to get in, so I was laying for him." + "Why didn't you roust me out?" + "Well, I tried to, but I couldn't; I couldn't budge you." + "Well, all right. + Don't stand there palavering all day, but out with you and see if there's a fish on the lines for breakfast. + I'll be along in a minute." + He unlocked the door, and I cleared out up the river-bank. + I noticed some pieces of limbs and such things floating down, and a sprinkling of bark; so I knowed the river had begun to rise. + I reckoned I would have great times now if I was over at the town. + The June rise used to be always luck for me; because as soon as that rise begins here comes cordwood floating down, and pieces of log rafts—sometimes a dozen logs together; so all you have to do is to catch them and sell them to the wood-yards and the sawmill. + I went along up the bank with one eye out for pap and t'other one out for what the rise might fetch along. + Well, all at once here comes a canoe; just a beauty, too, about thirteen or fourteen foot long, riding high like a duck. + I shot head-first off of the bank like a frog, clothes and all on, and struck out for the canoe. + I just expected there'd be somebody laying down in it, because people often done that to fool folks, and when a chap had pulled a skiff out most to it they'd raise up and laugh at him. + But it warn't so this time. + It was a drift-canoe sure enough, and I clumb in and paddled her ashore. + Thinks I, the old man will be glad when he sees this—she's worth ten dollars. + But when I got to shore pap wasn't in sight yet, and as I was running her into a little creek like a gully, all hung over with vines and willows, I struck another idea: I judged I'd hide her good, and then, 'stead of taking to the woods when I run off, I'd go down the river about fifty mile and camp in one place for good, and not have such a rough time tramping on foot. + It was pretty close to the shanty, and I thought I heard the old man coming all the time; but I got her hid; and then I out and looked around a bunch of willows, and there was the old man down the path a piece just drawing a bead on a bird with his gun. + So he hadn't seen anything. + When he got along I was hard at it taking up a "trot" line. + He abused me a little for being so slow; but I told him I fell in the river, and that was what made me so long. + I knowed he would see I was wet, and then he would be asking questions. + We got five catfish off the lines and went home. + While we laid off after breakfast to sleep up, both of us being about wore out, I got to thinking that if I could fix up some way to keep pap and the widow from trying to follow me, it would be a certainer thing than trusting to luck to get far enough off before they missed me; you see, all kinds of things might happen. + Well, I didn't see no way for a while, but by and by pap raised up a minute to drink another barrel of water, and he says: "Another time a man comes a-prowling round here you roust me out, you hear? + That man warn't here for no good. + I'd a shot him. + Next time you roust me out, you hear?" + Then he dropped down and went to sleep again; but what he had been saying give me the very idea I wanted. + I says to myself, I can fix it now so nobody won't think of following me. + About twelve o'clock we turned out and went along up the bank. + The river was coming up pretty fast, and lots of driftwood going by on the rise. + By and by along comes part of a log raft—nine logs fast together. + We went out with the skiff and towed it ashore. + Then we had dinner. + Anybody but pap would a waited and seen the day through, so as to catch more stuff; but that warn't pap's style. + Nine logs was enough for one time; he must shove right over to town and sell. + So he locked me in and took the skiff, and started off towing the raft about half-past three. + I judged he wouldn't come back that night. + I waited till I reckoned he had got a good start; then I out with my saw, and went to work on that log again. + Before he was t'other side of the river I was out of the hole; him and his raft was just a speck on the water away off yonder. + I took the sack of corn meal and took it to where the canoe was hid, and shoved the vines and branches apart and put it in; then I done the same with the side of bacon; then the whisky-jug. + I took all the coffee and sugar there was, and all the ammunition; I took the wadding; I took the bucket and gourd; I took a dipper and a tin cup, and my old saw and two blankets, and the skillet and the coffee-pot. + I took fish-lines and matches and other things—everything that was worth a cent. + I cleaned out the place. + I wanted an axe, but there wasn't any, only the one out at the woodpile, and I knowed why I was going to leave that. + I fetched out the gun, and now I was done. + I had wore the ground a good deal crawling out of the hole and dragging out so many things. + So I fixed that as good as I could from the outside by scattering dust on the place, which covered up the smoothness and the sawdust. + Then I fixed the piece of log back into its place, and put two rocks under it and one against it to hold it there, for it was bent up at that place and didn't quite touch ground. + If you stood four or five foot away and didn't know it was sawed, you wouldn't never notice it; and besides, this was the back of the cabin, and it warn't likely anybody would go fooling around there. + It was all grass clear to the canoe, so I hadn't left a track. + I followed around to see. + I stood on the bank and looked out over the river. + All safe. + So I took the gun and went up a piece into the woods, and was hunting around for some birds when I see a wild pig; hogs soon went wild in them bottoms after they had got away from the prairie farms. + I shot this fellow and took him into camp. + I took the axe and smashed in the door. + I beat it and hacked it considerable a-doing it. + I fetched the pig in, and took him back nearly to the table and hacked into his throat with the axe, and laid him down on the ground to bleed; I say ground because it was ground—hard packed, and no boards. + Well, next I took an old sack and put a lot of big rocks in it—all I could drag—and I started it from the pig, and dragged it to the door and through the woods down to the river and dumped it in, and down it sunk, out of sight. + You could easy see that something had been dragged over the ground. + I did wish Tom Sawyer was there; I knowed he would take an interest in this kind of business, and throw in the fancy touches. + Nobody could spread himself like Tom Sawyer in such a thing as that. + Well, last I pulled out some of my hair, and blooded the axe good, and stuck it on the back side, and slung the axe in the corner. + Then I took up the pig and held him to my breast with my jacket (so he couldn't drip) till I got a good piece below the house and then dumped him into the river. + Now I thought of something else. + So I went and got the bag of meal and my old saw out of the canoe, and fetched them to the house. + I took the bag to where it used to stand, and ripped a hole in the bottom of it with the saw, for there warn't no knives and forks on the place—pap done everything with his clasp-knife about the cooking. + Then I carried the sack about a hundred yards across the grass and through the willows east of the house, to a shallow lake that was five mile wide and full of rushes—and ducks too, you might say, in the season. + There was a slough or a creek leading out of it on the other side that went miles away, I don't know where, but it didn't go to the river. + The meal sifted out and made a little track all the way to the lake. + I dropped pap's whetstone there too, so as to look like it had been done by accident. + Then I tied up the rip in the meal sack with a string, so it wouldn't leak no more, and took it and my saw to the canoe again. + It was about dark now; so I dropped the canoe down the river under some willows that hung over the bank, and waited for the moon to rise. + I made fast to a willow; then I took a bite to eat, and by and by laid down in the canoe to smoke a pipe and lay out a plan. + I says to myself, they'll follow the track of that sackful of rocks to the shore and then drag the river for me. + And they'll follow that meal track to the lake and go browsing down the creek that leads out of it to find the robbers that killed me and took the things. + They won't ever hunt the river for anything but my dead carcass. + They'll soon get tired of that, and won't bother no more about me. + All right; I can stop anywhere I want to. + Jackson's Island is good enough for me; I know that island pretty well, and nobody ever comes there. + And then I can paddle over to town nights, and slink around and pick up things I want. + Jackson's Island's the place. + I was pretty tired, and the first thing I knowed I was asleep. + When I woke up I didn't know where I was for a minute. + I set up and looked around, a little scared. + Then I remembered. + The river looked miles and miles across. + The moon was so bright I could a counted the drift logs that went a-slipping along, black and still, hundreds of yards out from shore. + Everything was dead quiet, and it looked late, and _smelt_ late. + You know what I mean—I don't know the words to put it in. + I took a good gap and a stretch, and was just going to unhitch and start when I heard a sound away over the water. + I listened. + Pretty soon I made it out. + It was that dull kind of a regular sound that comes from oars working in rowlocks when it's a still night. + I peeped out through the willow branches, and there it was—a skiff, away across the water. + I couldn't tell how many was in it. + It kept a-coming, and when it was abreast of me I see there warn't but one man in it. + Think's I, maybe it's pap, though I warn't expecting him. + He dropped below me with the current, and by and by he came a-swinging up shore in the easy water, and he went by so close I could a reached out the gun and touched him. + Well, it _was_ pap, sure enough—and sober, too, by the way he laid his oars. + I didn't lose no time. + The next minute I was a-spinning down stream soft but quick in the shade of the bank. + I made two mile and a half, and then struck out a quarter of a mile or more towards the middle of the river, because pretty soon I would be passing the ferry landing, and people might see me and hail me. + I got out amongst the driftwood, and then laid down in the bottom of the canoe and let her float. + I laid there, and had a good rest and a smoke out of my pipe, looking away into the sky; not a cloud in it. + The sky looks ever so deep when you lay down on your back in the moonshine; I never knowed it before. + And how far a body can hear on the water such nights! + I heard people talking at the ferry landing. + I heard what they said, too—every word of it. + One man said it was getting towards the long days and the short nights now. + T'other one said _this_ warn't one of the short ones, he reckoned—and then they laughed, and he said it over again, and they laughed again; then they waked up another fellow and told him, and laughed, but he didn't laugh; he ripped out something brisk, and said let him alone. + The first fellow said he 'lowed to tell it to his old woman—she would think it was pretty good; but he said that warn't nothing to some things he had said in his time. + I heard one man say it was nearly three o'clock, and he hoped daylight wouldn't wait more than about a week longer. + After that the talk got further and further away, and I couldn't make out the words any more; but I could hear the mumble, and now and then a laugh, too, but it seemed a long ways off. + I was away below the ferry now. + I rose up, and there was Jackson's Island, about two mile and a half down stream, heavy timbered and standing up out of the middle of the river, big and dark and solid, like a steamboat without any lights. + There warn't any signs of the bar at the head—it was all under water now. + It didn't take me long to get there. + I shot past the head at a ripping rate, the current was so swift, and then I got into the dead water and landed on the side towards the Illinois shore. + I run the canoe into a deep dent in the bank that I knowed about; I had to part the willow branches to get in; and when I made fast nobody could a seen the canoe from the outside. + I went up and set down on a log at the head of the island, and looked out on the big river and the black driftwood and away over to the town, three mile away, where there was three or four lights twinkling. + A monstrous big lumber-raft was about a mile up stream, coming along down, with a lantern in the middle of it. + I watched it come creeping down, and when it was most abreast of where I stood I heard a man say, "Stern oars, there! + heave her head to stabboard!" + I heard that just as plain as if the man was by my side. + There was a little gray in the sky now; so I stepped into the woods, and laid down for a nap before breakfast. + CHAPTER VIII. + THE sun was up so high when I waked that I judged it was after eight o'clock. + I laid there in the grass and the cool shade thinking about things, and feeling rested and ruther comfortable and satisfied. + I could see the sun out at one or two holes, but mostly it was big trees all about, and gloomy in there amongst them. + There was freckled places on the ground where the light sifted down through the leaves, and the freckled places swapped about a little, showing there was a little breeze up there. + A couple of squirrels set on a limb and jabbered at me very friendly. + I was powerful lazy and comfortable—didn't want to get up and cook breakfast. + Well, I was dozing off again when I thinks I hears a deep sound of "boom!" + away up the river. + I rouses up, and rests on my elbow and listens; pretty soon I hears it again. + I hopped up, and went and looked out at a hole in the leaves, and I see a bunch of smoke laying on the water a long ways up—about abreast the ferry. + And there was the ferryboat full of people floating along down. + I knowed what was the matter now. + "Boom!" + I see the white smoke squirt out of the ferryboat's side. + You see, they was firing cannon over the water, trying to make my carcass come to the top. + I was pretty hungry, but it warn't going to do for me to start a fire, because they might see the smoke. + So I set there and watched the cannon-smoke and listened to the boom. + The river was a mile wide there, and it always looks pretty on a summer morning—so I was having a good enough time seeing them hunt for my remainders if I only had a bite to eat. + Well, then I happened to think how they always put quicksilver in loaves of bread and float them off, because they always go right to the drownded carcass and stop there. + So, says I, I'll keep a lookout, and if any of them's floating around after me I'll give them a show. + I changed to the Illinois edge of the island to see what luck I could have, and I warn't disappointed. + A big double loaf come along, and I most got it with a long stick, but my foot slipped and she floated out further. + Of course I was where the current set in the closest to the shore—I knowed enough for that. + But by and by along comes another one, and this time I won. + I took out the plug and shook out the little dab of quicksilver, and set my teeth in. + It was "baker's bread"—what the quality eat; none of your low-down corn-pone. + I got a good place amongst the leaves, and set there on a log, munching the bread and watching the ferry-boat, and very well satisfied. + And then something struck me. + I says, now I reckon the widow or the parson or somebody prayed that this bread would find me, and here it has gone and done it. + So there ain't no doubt but there is something in that thing—that is, there's something in it when a body like the widow or the parson prays, but it don't work for me, and I reckon it don't work for only just the right kind. + I lit a pipe and had a good long smoke, and went on watching. + The ferryboat was floating with the current, and I allowed I'd have a chance to see who was aboard when she come along, because she would come in close, where the bread did. + When she'd got pretty well along down towards me, I put out my pipe and went to where I fished out the bread, and laid down behind a log on the bank in a little open place. + Where the log forked I could peep through. + By and by she come along, and she drifted in so close that they could a run out a plank and walked ashore. + Most everybody was on the boat. + Pap, and Judge Thatcher, and Bessie Thatcher, and Jo Harper, and Tom Sawyer, and his old Aunt Polly, and Sid and Mary, and plenty more. + Everybody was talking about the murder, but the captain broke in and says: "Look sharp, now; the current sets in the closest here, and maybe he's washed ashore and got tangled amongst the brush at the water's edge. + I hope so, anyway." + I didn't hope so. + They all crowded up and leaned over the rails, nearly in my face, and kept still, watching with all their might. + I could see them first-rate, but they couldn't see me. + Then the captain sung out: "Stand away!" + and the cannon let off such a blast right before me that it made me deef with the noise and pretty near blind with the smoke, and I judged I was gone. + If they'd a had some bullets in, I reckon they'd a got the corpse they was after. + Well, I see I warn't hurt, thanks to goodness. + The boat floated on and went out of sight around the shoulder of the island. + I could hear the booming now and then, further and further off, and by and by, after an hour, I didn't hear it no more. + The island was three mile long. + I judged they had got to the foot, and was giving it up. + But they didn't yet a while. + They turned around the foot of the island and started up the channel on the Missouri side, under steam, and booming once in a while as they went. + I crossed over to that side and watched them. + When they got abreast the head of the island they quit shooting and dropped over to the Missouri shore and went home to the town. + I knowed I was all right now. + Nobody else would come a-hunting after me. + I got my traps out of the canoe and made me a nice camp in the thick woods. + I made a kind of a tent out of my blankets to put my things under so the rain couldn't get at them. + I catched a catfish and haggled him open with my saw, and towards sundown I started my camp fire and had supper. + Then I set out a line to catch some fish for breakfast. + When it was dark I set by my camp fire smoking, and feeling pretty well satisfied; but by and by it got sort of lonesome, and so I went and set on the bank and listened to the current swashing along, and counted the stars and drift logs and rafts that come down, and then went to bed; there ain't no better way to put in time when you are lonesome; you can't stay so, you soon get over it. + And so for three days and nights. + No difference—just the same thing. + But the next day I went exploring around down through the island. + I was boss of it; it all belonged to me, so to say, and I wanted to know all about it; but mainly I wanted to put in the time. + I found plenty strawberries, ripe and prime; and green summer grapes, and green razberries; and the green blackberries was just beginning to show. + They would all come handy by and by, I judged. + Well, I went fooling along in the deep woods till I judged I warn't far from the foot of the island. + I had my gun along, but I hadn't shot nothing; it was for protection; thought I would kill some game nigh home. + About this time I mighty near stepped on a good-sized snake, and it went sliding off through the grass and flowers, and I after it, trying to get a shot at it. + I clipped along, and all of a sudden I bounded right on to the ashes of a camp fire that was still smoking. + My heart jumped up amongst my lungs. + I never waited for to look further, but uncocked my gun and went sneaking back on my tiptoes as fast as ever I could. + Every now and then I stopped a second amongst the thick leaves and listened, but my breath come so hard I couldn't hear nothing else. + I slunk along another piece further, then listened again; and so on, and so on. + If I see a stump, I took it for a man; if I trod on a stick and broke it, it made me feel like a person had cut one of my breaths in two and I only got half, and the short half, too. + When I got to camp I warn't feeling very brash, there warn't much sand in my craw; but I says, this ain't no time to be fooling around. + So I got all my traps into my canoe again so as to have them out of sight, and I put out the fire and scattered the ashes around to look like an old last year's camp, and then clumb a tree. + I reckon I was up in the tree two hours; but I didn't see nothing, I didn't hear nothing—I only _thought_ I heard and seen as much as a thousand things. + Well, I couldn't stay up there forever; so at last I got down, but I kept in the thick woods and on the lookout all the time. + All I could get to eat was berries and what was left over from breakfast. + By the time it was night I was pretty hungry. + So when it was good and dark I slid out from shore before moonrise and paddled over to the Illinois bank—about a quarter of a mile. + I went out in the woods and cooked a supper, and I had about made up my mind I would stay there all night when I hear a _plunkety-plunk, plunkety-plunk_, and says to myself, horses coming; and next I hear people's voices. + I got everything into the canoe as quick as I could, and then went creeping through the woods to see what I could find out. + I hadn't got far when I hear a man say: "We better camp here if we can find a good place; the horses is about beat out. + Let's look around." + I didn't wait, but shoved out and paddled away easy. + I tied up in the old place, and reckoned I would sleep in the canoe. + I didn't sleep much. + I couldn't, somehow, for thinking. + And every time I waked up I thought somebody had me by the neck. + So the sleep didn't do me no good. + By and by I says to myself, I can't live this way; I'm a-going to find out who it is that's here on the island with me; I'll find it out or bust. + Well, I felt better right off. + So I took my paddle and slid out from shore just a step or two, and then let the canoe drop along down amongst the shadows. + The moon was shining, and outside of the shadows it made it most as light as day. + I poked along well on to an hour, everything still as rocks and sound asleep. + Well, by this time I was most down to the foot of the island. + A little ripply, cool breeze begun to blow, and that was as good as saying the night was about done. + I give her a turn with the paddle and brung her nose to shore; then I got my gun and slipped out and into the edge of the woods. + I sat down there on a log, and looked out through the leaves. + I see the moon go off watch, and the darkness begin to blanket the river. + But in a little while I see a pale streak over the treetops, and knowed the day was coming. + So I took my gun and slipped off towards where I had run across that camp fire, stopping every minute or two to listen. + But I hadn't no luck somehow; I couldn't seem to find the place. + But by and by, sure enough, I catched a glimpse of fire away through the trees. + I went for it, cautious and slow. + By and by I was close enough to have a look, and there laid a man on the ground. + It most give me the fan-tods. + He had a blanket around his head, and his head was nearly in the fire. + I set there behind a clump of bushes, in about six foot of him, and kept my eyes on him steady. + It was getting gray daylight now. + Pretty soon he gapped and stretched himself and hove off the blanket, and it was Miss Watson's Jim! + I bet I was glad to see him. + I says: "Hello, Jim!" + and skipped out. + He bounced up and stared at me wild. + Then he drops down on his knees, and puts his hands together and says: "Doan' hurt me—don't! + I hain't ever done no harm to a ghos'. + I alwuz liked dead people, en done all I could for 'em. + You go en git in de river agin, whah you b'longs, en doan' do nuffn to Ole Jim, 'at 'uz awluz yo' fren'." + Well, I warn't long making him understand I warn't dead. + I was ever so glad to see Jim. + I warn't lonesome now. + I told him I warn't afraid of _him_ telling the people where I was. + I talked along, but he only set there and looked at me; never said nothing. + Then I says: "It's good daylight. + Le's get breakfast. + Make up your camp fire good." + "What's de use er makin' up de camp fire to cook strawbries en sich truck? + But you got a gun, hain't you? + Den we kin git sumfn better den strawbries." + "Strawberries and such truck," I says. + "Is that what you live on?" + "I couldn' git nuffn else," he says. + "Why, how long you been on the island, Jim?" + "I come heah de night arter you's killed." + "What, all that time?" + "Yes—indeedy." + "And ain't you had nothing but that kind of rubbage to eat?" + "No, sah—nuffn else." + "Well, you must be most starved, ain't you?" + "I reck'n I could eat a hoss. + I think I could. + How long you ben on de islan'?" + "Since the night I got killed." + "No! + W'y, what has you lived on? + But you got a gun. + Oh, yes, you got a gun. + Dat's good. + Now you kill sumfn en I'll make up de fire." + So we went over to where the canoe was, and while he built a fire in a grassy open place amongst the trees, I fetched meal and bacon and coffee, and coffee-pot and frying-pan, and sugar and tin cups, and the nigger was set back considerable, because he reckoned it was all done with witchcraft. + I catched a good big catfish, too, and Jim cleaned him with his knife, and fried him. + When breakfast was ready we lolled on the grass and eat it smoking hot. + Jim laid it in with all his might, for he was most about starved. + Then when we had got pretty well stuffed, we laid off and lazied. + By and by Jim says: "But looky here, Huck, who wuz it dat 'uz killed in dat shanty ef it warn't you?" + Then I told him the whole thing, and he said it was smart. + He said Tom Sawyer couldn't get up no better plan than what I had. + Then I says: "How do you come to be here, Jim, and how'd you get here?" + He looked pretty uneasy, and didn't say nothing for a minute. + Then he says: "Maybe I better not tell." + "Why, Jim?" + "Well, dey's reasons. + But you wouldn' tell on me ef I uz to tell you, would you, Huck?" + "Blamed if I would, Jim." + "Well, I b'lieve you, Huck. + I—_I run off_." + "Jim!" + "But mind, you said you wouldn' tell—you know you said you wouldn' tell, Huck." + "Well, I did. + I said I wouldn't, and I'll stick to it. + Honest _injun_, I will. + People would call me a low-down Abolitionist and despise me for keeping mum—but that don't make no difference. + I ain't a-going to tell, and I ain't a-going back there, anyways. + So, now, le's know all about it." + "Well, you see, it 'uz dis way. + Ole missus—dat's Miss Watson—she pecks on me all de time, en treats me pooty rough, but she awluz said she wouldn' sell me down to Orleans. + But I noticed dey wuz a nigger trader roun' de place considable lately, en I begin to git oneasy. + Well, one night I creeps to de do' pooty late, en de do' warn't quite shet, en I hear old missus tell de widder she gwyne to sell me down to Orleans, but she didn' want to, but she could git eight hund'd dollars for me, en it 'uz sich a big stack o' money she couldn' resis'. + De widder she try to git her to say she wouldn' do it, but I never waited to hear de res'. + I lit out mighty quick, I tell you. + "I tuck out en shin down de hill, en 'spec to steal a skift 'long de sho' som'ers 'bove de town, but dey wuz people a-stirring yit, so I hid in de ole tumble-down cooper-shop on de bank to wait for everybody to go 'way. + Well, I wuz dah all night. + Dey wuz somebody roun' all de time. + 'Long 'bout six in de mawnin' skifts begin to go by, en 'bout eight er nine every skift dat went 'long wuz talkin' 'bout how yo' pap come over to de town en say you's killed. + Dese las' skifts wuz full o' ladies en genlmen a-goin' over for to see de place. + Sometimes dey'd pull up at de sho' en take a res' b'fo' dey started acrost, so by de talk I got to know all 'bout de killin'. + I 'uz powerful sorry you's killed, Huck, but I ain't no mo' now. + "I laid dah under de shavin's all day. + I 'uz hungry, but I warn't afeard; bekase I knowed ole missus en de widder wuz goin' to start to de camp-meet'n' right arter breakfas' en be gone all day, en dey knows I goes off wid de cattle 'bout daylight, so dey wouldn' 'spec to see me roun' de place, en so dey wouldn' miss me tell arter dark in de evenin'. + De yuther servants wouldn' miss me, kase dey'd shin out en take holiday soon as de ole folks 'uz out'n de way. + "Well, when it come dark I tuck out up de river road, en went 'bout two mile er more to whah dey warn't no houses. + I'd made up my mine 'bout what I's agwyne to do. + You see, ef I kep' on tryin' to git away afoot, de dogs 'ud track me; ef I stole a skift to cross over, dey'd miss dat skift, you see, en dey'd know 'bout whah I'd lan' on de yuther side, en whah to pick up my track. + So I says, a raff is what I's arter; it doan' _make_ no track. + "I see a light a-comin' roun' de p'int bymeby, so I wade' in en shove' a log ahead o' me en swum more'n half way acrost de river, en got in 'mongst de drift-wood, en kep' my head down low, en kinder swum agin de current tell de raff come along. + Den I swum to de stern uv it en tuck a-holt. + It clouded up en 'uz pooty dark for a little while. + So I clumb up en laid down on de planks. + De men 'uz all 'way yonder in de middle, whah de lantern wuz. + De river wuz a-risin', en dey wuz a good current; so I reck'n'd 'at by fo' in de mawnin' I'd be twenty-five mile down de river, en den I'd slip in jis b'fo' daylight en swim asho', en take to de woods on de Illinois side. + "But I didn' have no luck. + When we 'uz mos' down to de head er de islan' a man begin to come aft wid de lantern, I see it warn't no use fer to wait, so I slid overboard en struck out fer de islan'. + Well, I had a notion I could lan' mos' anywhers, but I couldn't—bank too bluff. + I 'uz mos' to de foot er de islan' b'fo' I found' a good place. + I went into de woods en jedged I wouldn' fool wid raffs no mo', long as dey move de lantern roun' so. + I had my pipe en a plug er dog-leg, en some matches in my cap, en dey warn't wet, so I 'uz all right." + "And so you ain't had no meat nor bread to eat all this time? + Why didn't you get mud-turkles?" + "How you gwyne to git 'm? + You can't slip up on um en grab um; en how's a body gwyne to hit um wid a rock? + How could a body do it in de night? + En I warn't gwyne to show mysef on de bank in de daytime." + "Well, that's so. + You've had to keep in the woods all the time, of course. + Did you hear 'em shooting the cannon?" + "Oh, yes. + I knowed dey was arter you. + I see um go by heah—watched um thoo de bushes." + Some young birds come along, flying a yard or two at a time and lighting. + Jim said it was a sign it was going to rain. + He said it was a sign when young chickens flew that way, and so he reckoned it was the same way when young birds done it. + I was going to catch some of them, but Jim wouldn't let me. + He said it was death. + He said his father laid mighty sick once, and some of them catched a bird, and his old granny said his father would die, and he did. + And Jim said you mustn't count the things you are going to cook for dinner, because that would bring bad luck. + The same if you shook the table-cloth after sundown. + And he said if a man owned a beehive and that man died, the bees must be told about it before sun-up next morning, or else the bees would all weaken down and quit work and die. + Jim said bees wouldn't sting idiots; but I didn't believe that, because I had tried them lots of times myself, and they wouldn't sting me. + I had heard about some of these things before, but not all of them. + Jim knowed all kinds of signs. + He said he knowed most everything. + I said it looked to me like all the signs was about bad luck, and so I asked him if there warn't any good-luck signs. + He says: "Mighty few—an' _dey_ ain't no use to a body. + What you want to know when good luck's a-comin' for? + Want to keep it off?" + And he said: "Ef you's got hairy arms en a hairy breas', it's a sign dat you's agwyne to be rich. + Well, dey's some use in a sign like dat, 'kase it's so fur ahead. + You see, maybe you's got to be po' a long time fust, en so you might git discourage' en kill yo'sef 'f you didn' know by de sign dat you gwyne to be rich bymeby." + "Have you got hairy arms and a hairy breast, Jim?" + "What's de use to ax dat question? + Don't you see I has?" + "Well, are you rich?" + "No, but I ben rich wunst, and gwyne to be rich agin. + Wunst I had foteen dollars, but I tuck to specalat'n', en got busted out." + "What did you speculate in, Jim?" + "Well, fust I tackled stock." + "What kind of stock?" + "Why, live stock—cattle, you know. + I put ten dollars in a cow. + But I ain' gwyne to resk no mo' money in stock. + De cow up 'n' died on my han's." + "So you lost the ten dollars." + "No, I didn't lose it all. + I on'y los' 'bout nine of it. + I sole de hide en taller for a dollar en ten cents." + "You had five dollars and ten cents left. + Did you speculate any more?" + "Yes. + You know that one-laigged nigger dat b'longs to old Misto Bradish? + Well, he sot up a bank, en say anybody dat put in a dollar would git fo' dollars mo' at de en' er de year. + Well, all de niggers went in, but dey didn't have much. + I wuz de on'y one dat had much. + So I stuck out for mo' dan fo' dollars, en I said 'f I didn' git it I'd start a bank mysef. + Well, o' course dat nigger want' to keep me out er de business, bekase he says dey warn't business 'nough for two banks, so he say I could put in my five dollars en he pay me thirty-five at de en' er de year. + "So I done it. + Den I reck'n'd I'd inves' de thirty-five dollars right off en keep things a-movin'. + Dey wuz a nigger name' Bob, dat had ketched a wood-flat, en his marster didn' know it; en I bought it off'n him en told him to take de thirty-five dollars when de en' er de year come; but somebody stole de wood-flat dat night, en nex day de one-laigged nigger say de bank's busted. + So dey didn' none uv us git no money." + "What did you do with the ten cents, Jim?" + "Well, I 'uz gwyne to spen' it, but I had a dream, en de dream tole me to give it to a nigger name' Balum—Balum's Ass dey call him for short; he's one er dem chuckleheads, you know. + But he's lucky, dey say, en I see I warn't lucky. + De dream say let Balum inves' de ten cents en he'd make a raise for me. + Well, Balum he tuck de money, en when he wuz in church he hear de preacher say dat whoever give to de po' len' to de Lord, en boun' to git his money back a hund'd times. + So Balum he tuck en give de ten cents to de po', en laid low to see what wuz gwyne to come of it." + "Well, what did come of it, Jim?" + "Nuffn never come of it. + I couldn' manage to k'leck dat money no way; en Balum he couldn'. + I ain' gwyne to len' no mo' money 'dout I see de security. + Boun' to git yo' money back a hund'd times, de preacher says! + Ef I could git de ten _cents_ back, I'd call it squah, en be glad er de chanst." + "Well, it's all right anyway, Jim, long as you're going to be rich again some time or other." + "Yes; en I's rich now, come to look at it. + I owns mysef, en I's wuth eight hund'd dollars. + I wisht I had de money, I wouldn' want no mo'." + CHAPTER IX. + I wanted to go and look at a place right about the middle of the island that I'd found when I was exploring; so we started and soon got to it, because the island was only three miles long and a quarter of a mile wide. + This place was a tolerable long, steep hill or ridge about forty foot high. + We had a rough time getting to the top, the sides was so steep and the bushes so thick. + We tramped and clumb around all over it, and by and by found a good big cavern in the rock, most up to the top on the side towards Illinois. + The cavern was as big as two or three rooms bunched together, and Jim could stand up straight in it. + It was cool in there. + Jim was for putting our traps in there right away, but I said we didn't want to be climbing up and down there all the time. + Jim said if we had the canoe hid in a good place, and had all the traps in the cavern, we could rush there if anybody was to come to the island, and they would never find us without dogs. + And, besides, he said them little birds had said it was going to rain, and did I want the things to get wet? + So we went back and got the canoe, and paddled up abreast the cavern, and lugged all the traps up there. + Then we hunted up a place close by to hide the canoe in, amongst the thick willows. + We took some fish off of the lines and set them again, and begun to get ready for dinner. + The door of the cavern was big enough to roll a hogshead in, and on one side of the door the floor stuck out a little bit, and was flat and a good place to build a fire on. + So we built it there and cooked dinner. + We spread the blankets inside for a carpet, and eat our dinner in there. + We put all the other things handy at the back of the cavern. + Pretty soon it darkened up, and begun to thunder and lighten; so the birds was right about it. + Directly it begun to rain, and it rained like all fury, too, and I never see the wind blow so. + It was one of these regular summer storms. + It would get so dark that it looked all blue-black outside, and lovely; and the rain would thrash along by so thick that the trees off a little ways looked dim and spider-webby; and here would come a blast of wind that would bend the trees down and turn up the pale underside of the leaves; and then a perfect ripper of a gust would follow along and set the branches to tossing their arms as if they was just wild; and next, when it was just about the bluest and blackest—_FST_! + it was as bright as glory, and you'd have a little glimpse of tree-tops a-plunging about away off yonder in the storm, hundreds of yards further than you could see before; dark as sin again in a second, and now you'd hear the thunder let go with an awful crash, and then go rumbling, grumbling, tumbling, down the sky towards the under side of the world, like rolling empty barrels down stairs—where it's long stairs and they bounce a good deal, you know. + "Jim, this is nice," I says. + "I wouldn't want to be nowhere else but here. + Pass me along another hunk of fish and some hot corn-bread." + "Well, you wouldn't a ben here 'f it hadn't a ben for Jim. + You'd a ben down dah in de woods widout any dinner, en gittn' mos' drownded, too; dat you would, honey. + Chickens knows when it's gwyne to rain, en so do de birds, chile." + The river went on raising and raising for ten or twelve days, till at last it was over the banks. + The water was three or four foot deep on the island in the low places and on the Illinois bottom. + On that side it was a good many miles wide, but on the Missouri side it was the same old distance across—a half a mile—because the Missouri shore was just a wall of high bluffs. + Daytimes we paddled all over the island in the canoe, It was mighty cool and shady in the deep woods, even if the sun was blazing outside. + We went winding in and out amongst the trees, and sometimes the vines hung so thick we had to back away and go some other way. + Well, on every old broken-down tree you could see rabbits and snakes and such things; and when the island had been overflowed a day or two they got so tame, on account of being hungry, that you could paddle right up and put your hand on them if you wanted to; but not the snakes and turtles—they would slide off in the water. + The ridge our cavern was in was full of them. + We could a had pets enough if we'd wanted them. + One night we catched a little section of a lumber raft—nice pine planks. + It was twelve foot wide and about fifteen or sixteen foot long, and the top stood above water six or seven inches—a solid, level floor. + We could see saw-logs go by in the daylight sometimes, but we let them go; we didn't show ourselves in daylight. + Another night when we was up at the head of the island, just before daylight, here comes a frame-house down, on the west side. + She was a two-story, and tilted over considerable. + We paddled out and got aboard—clumb in at an upstairs window. + But it was too dark to see yet, so we made the canoe fast and set in her to wait for daylight. + The light begun to come before we got to the foot of the island. + Then we looked in at the window. + We could make out a bed, and a table, and two old chairs, and lots of things around about on the floor, and there was clothes hanging against the wall. + There was something laying on the floor in the far corner that looked like a man. + So Jim says: + "Hello, you!" + But it didn't budge. + So I hollered again, and then Jim says: + "De man ain't asleep—he's dead. + You hold still—I'll go en see." + He went, and bent down and looked, and says: + "It's a dead man. + Yes, indeedy; naked, too. + He's ben shot in de back. + I reck'n he's ben dead two er three days. + Come in, Huck, but doan' look at his face—it's too gashly." + I didn't look at him at all. + Jim throwed some old rags over him, but he needn't done it; I didn't want to see him. + There was heaps of old greasy cards scattered around over the floor, and old whisky bottles, and a couple of masks made out of black cloth; and all over the walls was the ignorantest kind of words and pictures made with charcoal. + There was two old dirty calico dresses, and a sun-bonnet, and some women's underclothes hanging against the wall, and some men's clothing, too. + We put the lot into the canoe—it might come good. + There was a boy's old speckled straw hat on the floor; I took that, too. + And there was a bottle that had had milk in it, and it had a rag stopper for a baby to suck. + We would a took the bottle, but it was broke. + There was a seedy old chest, and an old hair trunk with the hinges broke. + They stood open, but there warn't nothing left in them that was any account. + The way things was scattered about we reckoned the people left in a hurry, and warn't fixed so as to carry off most of their stuff. + We got an old tin lantern, and a butcher-knife without any handle, and a bran-new Barlow knife worth two bits in any store, and a lot of tallow candles, and a tin candlestick, and a gourd, and a tin cup, and a ratty old bedquilt off the bed, and a reticule with needles and pins and beeswax and buttons and thread and all such truck in it, and a hatchet and some nails, and a fishline as thick as my little finger with some monstrous hooks on it, and a roll of buckskin, and a leather dog-collar, and a horseshoe, and some vials of medicine that didn't have no label on them; and just as we was leaving I found a tolerable good curry-comb, and Jim he found a ratty old fiddle-bow, and a wooden leg. + The straps was broke off of it, but, barring that, it was a good enough leg, though it was too long for me and not long enough for Jim, and we couldn't find the other one, though we hunted all around. + And so, take it all around, we made a good haul. + When we was ready to shove off we was a quarter of a mile below the island, and it was pretty broad day; so I made Jim lay down in the canoe and cover up with the quilt, because if he set up people could tell he was a nigger a good ways off. + I paddled over to the Illinois shore, and drifted down most a half a mile doing it. + I crept up the dead water under the bank, and hadn't no accidents and didn't see nobody. + We got home all safe. + CHAPTER X. + AFTER breakfast I wanted to talk about the dead man and guess out how he come to be killed, but Jim didn't want to. + He said it would fetch bad luck; and besides, he said, he might come and ha'nt us; he said a man that warn't buried was more likely to go a-ha'nting around than one that was planted and comfortable. + That sounded pretty reasonable, so I didn't say no more; but I couldn't keep from studying over it and wishing I knowed who shot the man, and what they done it for. + We rummaged the clothes we'd got, and found eight dollars in silver sewed up in the lining of an old blanket overcoat. + Jim said he reckoned the people in that house stole the coat, because if they'd a knowed the money was there they wouldn't a left it. + I said I reckoned they killed him, too; but Jim didn't want to talk about that. + I says: + "Now you think it's bad luck; but what did you say when I fetched in the snake-skin that I found on the top of the ridge day before yesterday? + You said it was the worst bad luck in the world to touch a snake-skin with my hands. + Well, here's your bad luck! + We've raked in all this truck and eight dollars besides. + I wish we could have some bad luck like this every day, Jim." + "Never you mind, honey, never you mind. + Don't you git too peart. + It's a-comin'. + Mind I tell you, it's a-comin'." + It did come, too. + It was a Tuesday that we had that talk. + Well, after dinner Friday we was laying around in the grass at the upper end of the ridge, and got out of tobacco. + I went to the cavern to get some, and found a rattlesnake in there. + I killed him, and curled him up on the foot of Jim's blanket, ever so natural, thinking there'd be some fun when Jim found him there. + Well, by night I forgot all about the snake, and when Jim flung himself down on the blanket while I struck a light the snake's mate was there, and bit him. + He jumped up yelling, and the first thing the light showed was the varmint curled up and ready for another spring. + I laid him out in a second with a stick, and Jim grabbed pap's whisky-jug and begun to pour it down. + He was barefooted, and the snake bit him right on the heel. + That all comes of my being such a fool as to not remember that wherever you leave a dead snake its mate always comes there and curls around it. + Jim told me to chop off the snake's head and throw it away, and then skin the body and roast a piece of it. + I done it, and he eat it and said it would help cure him. + He made me take off the rattles and tie them around his wrist, too. + He said that that would help. + Then I slid out quiet and throwed the snakes clear away amongst the bushes; for I warn't going to let Jim find out it was all my fault, not if I could help it. + Jim sucked and sucked at the jug, and now and then he got out of his head and pitched around and yelled; but every time he come to himself he went to sucking at the jug again. + His foot swelled up pretty big, and so did his leg; but by and by the drunk begun to come, and so I judged he was all right; but I'd druther been bit with a snake than pap's whisky. + Jim was laid up for four days and nights. + Then the swelling was all gone and he was around again. + I made up my mind I wouldn't ever take a-holt of a snake-skin again with my hands, now that I see what had come of it. + Jim said he reckoned I would believe him next time. + And he said that handling a snake-skin was such awful bad luck that maybe we hadn't got to the end of it yet. + He said he druther see the new moon over his left shoulder as much as a thousand times than take up a snake-skin in his hand. + Well, I was getting to feel that way myself, though I've always reckoned that looking at the new moon over your left shoulder is one of the carelessest and foolishest things a body can do. + Old Hank Bunker done it once, and bragged about it; and in less than two years he got drunk and fell off of the shot-tower, and spread himself out so that he was just a kind of a layer, as you may say; and they slid him edgeways between two barn doors for a coffin, and buried him so, so they say, but I didn't see it. + Pap told me. + But anyway it all come of looking at the moon that way, like a fool. + Well, the days went along, and the river went down between its banks again; and about the first thing we done was to bait one of the big hooks with a skinned rabbit and set it and catch a catfish that was as big as a man, being six foot two inches long, and weighed over two hundred pounds. + We couldn't handle him, of course; he would a flung us into Illinois. + We just set there and watched him rip and tear around till he drownded. + We found a brass button in his stomach and a round ball, and lots of rubbage. + We split the ball open with the hatchet, and there was a spool in it. + Jim said he'd had it there a long time, to coat it over so and make a ball of it. + It was as big a fish as was ever catched in the Mississippi, I reckon. + Jim said he hadn't ever seen a bigger one. + He would a been worth a good deal over at the village. + They peddle out such a fish as that by the pound in the market-house there; everybody buys some of him; his meat's as white as snow and makes a good fry. + Next morning I said it was getting slow and dull, and I wanted to get a stirring up some way. + I said I reckoned I would slip over the river and find out what was going on. + Jim liked that notion; but he said I must go in the dark and look sharp. + Then he studied it over and said, couldn't I put on some of them old things and dress up like a girl? + That was a good notion, too. + So we shortened up one of the calico gowns, and I turned up my trouser-legs to my knees and got into it. + Jim hitched it behind with the hooks, and it was a fair fit. + I put on the sun-bonnet and tied it under my chin, and then for a body to look in and see my face was like looking down a joint of stove-pipe. + Jim said nobody would know me, even in the daytime, hardly. + I practiced around all day to get the hang of the things, and by and by I could do pretty well in them, only Jim said I didn't walk like a girl; and he said I must quit pulling up my gown to get at my britches-pocket. + I took notice, and done better. + I started up the Illinois shore in the canoe just after dark. + I started across to the town from a little below the ferry-landing, and the drift of the current fetched me in at the bottom of the town. + I tied up and started along the bank. + There was a light burning in a little shanty that hadn't been lived in for a long time, and I wondered who had took up quarters there. + I slipped up and peeped in at the window. + There was a woman about forty year old in there knitting by a candle that was on a pine table. + I didn't know her face; she was a stranger, for you couldn't start a face in that town that I didn't know. + Now this was lucky, because I was weakening; I was getting afraid I had come; people might know my voice and find me out. + But if this woman had been in such a little town two days she could tell me all I wanted to know; so I knocked at the door, and made up my mind I wouldn't forget I was a girl. + CHAPTER XI. + "COME in," says the woman, and I did. + She says: "Take a cheer." + I done it. + She looked me all over with her little shiny eyes, and says: + "What might your name be?" + "Sarah Williams." + "Where 'bouts do you live? + In this neighborhood?' + "No'm. + In Hookerville, seven mile below. + I've walked all the way and I'm all tired out." + "Hungry, too, I reckon. + I'll find you something." + "No'm, I ain't hungry. + I was so hungry I had to stop two miles below here at a farm; so I ain't hungry no more. + It's what makes me so late. + My mother's down sick, and out of money and everything, and I come to tell my uncle Abner Moore. + He lives at the upper end of the town, she says. + I hain't ever been here before. + Do you know him?" + "No; but I don't know everybody yet. + I haven't lived here quite two weeks. + It's a considerable ways to the upper end of the town. + You better stay here all night. + Take off your bonnet." + "No," I says; "I'll rest a while, I reckon, and go on. + I ain't afeared of the dark." + She said she wouldn't let me go by myself, but her husband would be in by and by, maybe in a hour and a half, and she'd send him along with me. + Then she got to talking about her husband, and about her relations up the river, and her relations down the river, and about how much better off they used to was, and how they didn't know but they'd made a mistake coming to our town, instead of letting well alone—and so on and so on, till I was afeard I had made a mistake coming to her to find out what was going on in the town; but by and by she dropped on to pap and the murder, and then I was pretty willing to let her clatter right along. + She told about me and Tom Sawyer finding the six thousand dollars (only she got it ten) and all about pap and what a hard lot he was, and what a hard lot I was, and at last she got down to where I was murdered. + I says: + "Who done it? + We've heard considerable about these goings on down in Hookerville, but we don't know who 'twas that killed Huck Finn." + "Well, I reckon there's a right smart chance of people _here_ that'd like to know who killed him. + Some think old Finn done it himself." + "No—is that so?" + "Most everybody thought it at first. + He'll never know how nigh he come to getting lynched. + But before night they changed around and judged it was done by a runaway nigger named Jim." + "Why _he_—" + I stopped. + I reckoned I better keep still. + She run on, and never noticed I had put in at all: + "The nigger run off the very night Huck Finn was killed. + So there's a reward out for him—three hundred dollars. + And there's a reward out for old Finn, too—two hundred dollars. + You see, he come to town the morning after the murder, and told about it, and was out with 'em on the ferryboat hunt, and right away after he up and left. + Before night they wanted to lynch him, but he was gone, you see. + Well, next day they found out the nigger was gone; they found out he hadn't ben seen sence ten o'clock the night the murder was done. + So then they put it on him, you see; and while they was full of it, next day, back comes old Finn, and went boo-hooing to Judge Thatcher to get money to hunt for the nigger all over Illinois with. + The judge gave him some, and that evening he got drunk, and was around till after midnight with a couple of mighty hard-looking strangers, and then went off with them. + Well, he hain't come back sence, and they ain't looking for him back till this thing blows over a little, for people thinks now that he killed his boy and fixed things so folks would think robbers done it, and then he'd get Huck's money without having to bother a long time with a lawsuit. + People do say he warn't any too good to do it. + Oh, he's sly, I reckon. + If he don't come back for a year he'll be all right. + You can't prove anything on him, you know; everything will be quieted down then, and he'll walk in Huck's money as easy as nothing." + "Yes, I reckon so, 'm. + I don't see nothing in the way of it. + Has everybody quit thinking the nigger done it?" + "Oh, no, not everybody. + A good many thinks he done it. + But they'll get the nigger pretty soon now, and maybe they can scare it out of him." + "Why, are they after him yet?" + "Well, you're innocent, ain't you! + Does three hundred dollars lay around every day for people to pick up? + Some folks think the nigger ain't far from here. + I'm one of them—but I hain't talked it around. + A few days ago I was talking with an old couple that lives next door in the log shanty, and they happened to say hardly anybody ever goes to that island over yonder that they call Jackson's Island. + Don't anybody live there? + says I. No, nobody, says they. + I didn't say any more, but I done some thinking. + I was pretty near certain I'd seen smoke over there, about the head of the island, a day or two before that, so I says to myself, like as not that nigger's hiding over there; anyway, says I, it's worth the trouble to give the place a hunt. + I hain't seen any smoke sence, so I reckon maybe he's gone, if it was him; but husband's going over to see—him and another man. + He was gone up the river; but he got back to-day, and I told him as soon as he got here two hours ago." + I had got so uneasy I couldn't set still. + I had to do something with my hands; so I took up a needle off of the table and went to threading it. + My hands shook, and I was making a bad job of it. + When the woman stopped talking I looked up, and she was looking at me pretty curious and smiling a little. + I put down the needle and thread, and let on to be interested—and I was, too—and says: + "Three hundred dollars is a power of money. + I wish my mother could get it. + Is your husband going over there to-night?" + "Oh, yes. + He went up-town with the man I was telling you of, to get a boat and see if they could borrow another gun. + They'll go over after midnight." + "Couldn't they see better if they was to wait till daytime?" + "Yes. + And couldn't the nigger see better, too? + After midnight he'll likely be asleep, and they can slip around through the woods and hunt up his camp fire all the better for the dark, if he's got one." + "I didn't think of that." + The woman kept looking at me pretty curious, and I didn't feel a bit comfortable. + Pretty soon she says, + "What did you say your name was, honey?" + "M—Mary Williams." + Somehow it didn't seem to me that I said it was Mary before, so I didn't look up—seemed to me I said it was Sarah; so I felt sort of cornered, and was afeared maybe I was looking it, too. + I wished the woman would say something more; the longer she set still the uneasier I was. + But now she says: + "Honey, I thought you said it was Sarah when you first come in?" + "Oh, yes'm, I did. + Sarah Mary Williams. + Sarah's my first name. + Some calls me Sarah, some calls me Mary." + "Oh, that's the way of it?" + "Yes'm." + I was feeling better then, but I wished I was out of there, anyway. + I couldn't look up yet. + Well, the woman fell to talking about how hard times was, and how poor they had to live, and how the rats was as free as if they owned the place, and so forth and so on, and then I got easy again. + She was right about the rats. + You'd see one stick his nose out of a hole in the corner every little while. + She said she had to have things handy to throw at them when she was alone, or they wouldn't give her no peace. + She showed me a bar of lead twisted up into a knot, and said she was a good shot with it generly, but she'd wrenched her arm a day or two ago, and didn't know whether she could throw true now. + But she watched for a chance, and directly banged away at a rat; but she missed him wide, and said "Ouch!" + it hurt her arm so. + Then she told me to try for the next one. + I wanted to be getting away before the old man got back, but of course I didn't let on. + I got the thing, and the first rat that showed his nose I let drive, and if he'd a stayed where he was he'd a been a tolerable sick rat. + She said that was first-rate, and she reckoned I would hive the next one. + She went and got the lump of lead and fetched it back, and brought along a hank of yarn which she wanted me to help her with. + I held up my two hands and she put the hank over them, and went on talking about her and her husband's matters. + But she broke off to say: + "Keep your eye on the rats. + You better have the lead in your lap, handy." + So she dropped the lump into my lap just at that moment, and I clapped my legs together on it and she went on talking. + But only about a minute. + Then she took off the hank and looked me straight in the face, and very pleasant, and says: + "Come, now, what's your real name?" + "Wh—what, mum?" + "What's your real name? + Is it Bill, or Tom, or Bob? + —or what is it?" + I reckon I shook like a leaf, and I didn't know hardly what to do. + But I says: + "Please to don't poke fun at a poor girl like me, mum. + If I'm in the way here, I'll—" + "No, you won't. + Set down and stay where you are. + I ain't going to hurt you, and I ain't going to tell on you, nuther. + You just tell me your secret, and trust me. + I'll keep it; and, what's more, I'll help you. + So'll my old man if you want him to. + You see, you're a runaway 'prentice, that's all. + It ain't anything. + There ain't no harm in it. + You've been treated bad, and you made up your mind to cut. + Bless you, child, I wouldn't tell on you. + Tell me all about it now, that's a good boy." + So I said it wouldn't be no use to try to play it any longer, and I would just make a clean breast and tell her everything, but she musn't go back on her promise. + Then I told her my father and mother was dead, and the law had bound me out to a mean old farmer in the country thirty mile back from the river, and he treated me so bad I couldn't stand it no longer; he went away to be gone a couple of days, and so I took my chance and stole some of his daughter's old clothes and cleared out, and I had been three nights coming the thirty miles. + I traveled nights, and hid daytimes and slept, and the bag of bread and meat I carried from home lasted me all the way, and I had a-plenty. + I said I believed my uncle Abner Moore would take care of me, and so that was why I struck out for this town of Goshen. + "Goshen, child? + This ain't Goshen. + This is St. Petersburg. + Goshen's ten mile further up the river. + Who told you this was Goshen?" + "Why, a man I met at daybreak this morning, just as I was going to turn into the woods for my regular sleep. + He told me when the roads forked I must take the right hand, and five mile would fetch me to Goshen." + "He was drunk, I reckon. + He told you just exactly wrong." + "Well, he did act like he was drunk, but it ain't no matter now. + I got to be moving along. + I'll fetch Goshen before daylight." + "Hold on a minute. + I'll put you up a snack to eat. + You might want it." + So she put me up a snack, and says: + "Say, when a cow's laying down, which end of her gets up first? + Answer up prompt now—don't stop to study over it. + Which end gets up first?" + "The hind end, mum." + "Well, then, a horse?" + "The for'rard end, mum." + "Which side of a tree does the moss grow on?" + "North side." + "If fifteen cows is browsing on a hillside, how many of them eats with their heads pointed the same direction?" + "The whole fifteen, mum." + "Well, I reckon you _have_ lived in the country. + I thought maybe you was trying to hocus me again. + What's your real name, now?" + "George Peters, mum." + "Well, try to remember it, George. + Don't forget and tell me it's Elexander before you go, and then get out by saying it's George Elexander when I catch you. + And don't go about women in that old calico. + You do a girl tolerable poor, but you might fool men, maybe. + Bless you, child, when you set out to thread a needle don't hold the thread still and fetch the needle up to it; hold the needle still and poke the thread at it; that's the way a woman most always does, but a man always does t'other way. + And when you throw at a rat or anything, hitch yourself up a tiptoe and fetch your hand up over your head as awkward as you can, and miss your rat about six or seven foot. + Throw stiff-armed from the shoulder, like there was a pivot there for it to turn on, like a girl; not from the wrist and elbow, with your arm out to one side, like a boy. + And, mind you, when a girl tries to catch anything in her lap she throws her knees apart; she don't clap them together, the way you did when you catched the lump of lead. + Why, I spotted you for a boy when you was threading the needle; and I contrived the other things just to make certain. + Now trot along to your uncle, Sarah Mary Williams George Elexander Peters, and if you get into trouble you send word to Mrs. Judith Loftus, which is me, and I'll do what I can to get you out of it. + Keep the river road all the way, and next time you tramp take shoes and socks with you. + The river road's a rocky one, and your feet'll be in a condition when you get to Goshen, I reckon." + I went up the bank about fifty yards, and then I doubled on my tracks and slipped back to where my canoe was, a good piece below the house. + I jumped in, and was off in a hurry. + I went up-stream far enough to make the head of the island, and then started across. + I took off the sun-bonnet, for I didn't want no blinders on then. + When I was about the middle I heard the clock begin to strike, so I stops and listens; the sound come faint over the water but clear—eleven. + When I struck the head of the island I never waited to blow, though I was most winded, but I shoved right into the timber where my old camp used to be, and started a good fire there on a high and dry spot. + Then I jumped in the canoe and dug out for our place, a mile and a half below, as hard as I could go. + I landed, and slopped through the timber and up the ridge and into the cavern. + There Jim laid, sound asleep on the ground. + I roused him out and says: + "Git up and hump yourself, Jim! + There ain't a minute to lose. + They're after us!" + Jim never asked no questions, he never said a word; but the way he worked for the next half an hour showed about how he was scared. + By that time everything we had in the world was on our raft, and she was ready to be shoved out from the willow cove where she was hid. + We put out the camp fire at the cavern the first thing, and didn't show a candle outside after that. + I took the canoe out from the shore a little piece, and took a look; but if there was a boat around I couldn't see it, for stars and shadows ain't good to see by. + Then we got out the raft and slipped along down in the shade, past the foot of the island dead still—never saying a word. + CHAPTER XII. + IT must a been close on to one o'clock when we got below the island at last, and the raft did seem to go mighty slow. + If a boat was to come along we was going to take to the canoe and break for the Illinois shore; and it was well a boat didn't come, for we hadn't ever thought to put the gun in the canoe, or a fishing-line, or anything to eat. + We was in ruther too much of a sweat to think of so many things. + It warn't good judgment to put _everything_ on the raft. + If the men went to the island I just expect they found the camp fire I built, and watched it all night for Jim to come. + Anyways, they stayed away from us, and if my building the fire never fooled them it warn't no fault of mine. + I played it as low down on them as I could. + When the first streak of day began to show we tied up to a towhead in a big bend on the Illinois side, and hacked off cottonwood branches with the hatchet, and covered up the raft with them so she looked like there had been a cave-in in the bank there. + A tow-head is a sandbar that has cottonwoods on it as thick as harrow-teeth. + We had mountains on the Missouri shore and heavy timber on the Illinois side, and the channel was down the Missouri shore at that place, so we warn't afraid of anybody running across us. + We laid there all day, and watched the rafts and steamboats spin down the Missouri shore, and up-bound steamboats fight the big river in the middle. + I told Jim all about the time I had jabbering with that woman; and Jim said she was a smart one, and if she was to start after us herself she wouldn't set down and watch a camp fire—no, sir, she'd fetch a dog. + Well, then, I said, why couldn't she tell her husband to fetch a dog? + Jim said he bet she did think of it by the time the men was ready to start, and he believed they must a gone up-town to get a dog and so they lost all that time, or else we wouldn't be here on a towhead sixteen or seventeen mile below the village—no, indeedy, we would be in that same old town again. + So I said I didn't care what was the reason they didn't get us as long as they didn't. + When it was beginning to come on dark we poked our heads out of the cottonwood thicket, and looked up and down and across; nothing in sight; so Jim took up some of the top planks of the raft and built a snug wigwam to get under in blazing weather and rainy, and to keep the things dry. + Jim made a floor for the wigwam, and raised it a foot or more above the level of the raft, so now the blankets and all the traps was out of reach of steamboat waves. + Right in the middle of the wigwam we made a layer of dirt about five or six inches deep with a frame around it for to hold it to its place; this was to build a fire on in sloppy weather or chilly; the wigwam would keep it from being seen. + We made an extra steering-oar, too, because one of the others might get broke on a snag or something. + We fixed up a short forked stick to hang the old lantern on, because we must always light the lantern whenever we see a steamboat coming down-stream, to keep from getting run over; but we wouldn't have to light it for up-stream boats unless we see we was in what they call a "crossing"; for the river was pretty high yet, very low banks being still a little under water; so up-bound boats didn't always run the channel, but hunted easy water. + This second night we run between seven and eight hours, with a current that was making over four mile an hour. + We catched fish and talked, and we took a swim now and then to keep off sleepiness. + It was kind of solemn, drifting down the big, still river, laying on our backs looking up at the stars, and we didn't ever feel like talking loud, and it warn't often that we laughed—only a little kind of a low chuckle. + We had mighty good weather as a general thing, and nothing ever happened to us at all—that night, nor the next, nor the next. + Every night we passed towns, some of them away up on black hillsides, nothing but just a shiny bed of lights; not a house could you see. + The fifth night we passed St. Louis, and it was like the whole world lit up. + In St. Petersburg they used to say there was twenty or thirty thousand people in St. Louis, but I never believed it till I see that wonderful spread of lights at two o'clock that still night. + There warn't a sound there; everybody was asleep. + Every night now I used to slip ashore towards ten o'clock at some little village, and buy ten or fifteen cents' worth of meal or bacon or other stuff to eat; and sometimes I lifted a chicken that warn't roosting comfortable, and took him along. + Pap always said, take a chicken when you get a chance, because if you don't want him yourself you can easy find somebody that does, and a good deed ain't ever forgot. + I never see pap when he didn't want the chicken himself, but that is what he used to say, anyway. + Mornings before daylight I slipped into cornfields and borrowed a watermelon, or a mushmelon, or a punkin, or some new corn, or things of that kind. + Pap always said it warn't no harm to borrow things if you was meaning to pay them back some time; but the widow said it warn't anything but a soft name for stealing, and no decent body would do it. + Jim said he reckoned the widow was partly right and pap was partly right; so the best way would be for us to pick out two or three things from the list and say we wouldn't borrow them any more—then he reckoned it wouldn't be no harm to borrow the others. + So we talked it over all one night, drifting along down the river, trying to make up our minds whether to drop the watermelons, or the cantelopes, or the mushmelons, or what. + But towards daylight we got it all settled satisfactory, and concluded to drop crabapples and p'simmons. + We warn't feeling just right before that, but it was all comfortable now. + I was glad the way it come out, too, because crabapples ain't ever good, and the p'simmons wouldn't be ripe for two or three months yet. + We shot a water-fowl now and then that got up too early in the morning or didn't go to bed early enough in the evening. + Take it all round, we lived pretty high. + The fifth night below St. Louis we had a big storm after midnight, with a power of thunder and lightning, and the rain poured down in a solid sheet. + We stayed in the wigwam and let the raft take care of itself. + When the lightning glared out we could see a big straight river ahead, and high, rocky bluffs on both sides. + By and by says I, "Hel-_lo_, Jim, looky yonder!" + It was a steamboat that had killed herself on a rock. + We was drifting straight down for her. + The lightning showed her very distinct. + She was leaning over, with part of her upper deck above water, and you could see every little chimbly-guy clean and clear, and a chair by the big bell, with an old slouch hat hanging on the back of it, when the flashes come. + Well, it being away in the night and stormy, and all so mysterious-like, I felt just the way any other boy would a felt when I see that wreck laying there so mournful and lonesome in the middle of the river. + I wanted to get aboard of her and slink around a little, and see what there was there. + So I says: + "Le's land on her, Jim." + But Jim was dead against it at first. + He says: + "I doan' want to go fool'n 'long er no wrack. + We's doin' blame' well, en we better let blame' well alone, as de good book says. + Like as not dey's a watchman on dat wrack." + "Watchman your grandmother," I says; "there ain't nothing to watch but the texas and the pilot-house; and do you reckon anybody's going to resk his life for a texas and a pilot-house such a night as this, when it's likely to break up and wash off down the river any minute?" + Jim couldn't say nothing to that, so he didn't try. + "And besides," I says, "we might borrow something worth having out of the captain's stateroom. + Seegars, I bet you—and cost five cents apiece, solid cash. + Steamboat captains is always rich, and get sixty dollars a month, and _they_ don't care a cent what a thing costs, you know, long as they want it. + Stick a candle in your pocket; I can't rest, Jim, till we give her a rummaging. + Do you reckon Tom Sawyer would ever go by this thing? + Not for pie, he wouldn't. + He'd call it an adventure—that's what he'd call it; and he'd land on that wreck if it was his last act. + And wouldn't he throw style into it? + —wouldn't he spread himself, nor nothing? + Why, you'd think it was Christopher C'lumbus discovering Kingdom-Come. + I wish Tom Sawyer _was_ here." + Jim he grumbled a little, but give in. + He said we mustn't talk any more than we could help, and then talk mighty low. + The lightning showed us the wreck again just in time, and we fetched the stabboard derrick, and made fast there. + The deck was high out here. + We went sneaking down the slope of it to labboard, in the dark, towards the texas, feeling our way slow with our feet, and spreading our hands out to fend off the guys, for it was so dark we couldn't see no sign of them. + Pretty soon we struck the forward end of the skylight, and clumb on to it; and the next step fetched us in front of the captain's door, which was open, and by Jimminy, away down through the texas-hall we see a light! + and all in the same second we seem to hear low voices in yonder! + Jim whispered and said he was feeling powerful sick, and told me to come along. + I says, all right, and was going to start for the raft; but just then I heard a voice wail out and say: + "Oh, please don't, boys; I swear I won't ever tell!" + Another voice said, pretty loud: + "It's a lie, Jim Turner. + You've acted this way before. + You always want more'n your share of the truck, and you've always got it, too, because you've swore 't if you didn't you'd tell. + But this time you've said it jest one time too many. + You're the meanest, treacherousest hound in this country." + By this time Jim was gone for the raft. + I was just a-biling with curiosity; and I says to myself, Tom Sawyer wouldn't back out now, and so I won't either; I'm a-going to see what's going on here. + So I dropped on my hands and knees in the little passage, and crept aft in the dark till there warn't but one stateroom betwixt me and the cross-hall of the texas. + Then in there I see a man stretched on the floor and tied hand and foot, and two men standing over him, and one of them had a dim lantern in his hand, and the other one had a pistol. + This one kept pointing the pistol at the man's head on the floor, and saying: + "I'd _like_ to! + And I orter, too—a mean skunk!" + The man on the floor would shrivel up and say, "Oh, please don't, Bill; I hain't ever goin' to tell." + And every time he said that the man with the lantern would laugh and say: + "'Deed you _ain't! + _ You never said no truer thing 'n that, you bet you." + And once he said: "Hear him beg! + and yit if we hadn't got the best of him and tied him he'd a killed us both. + And what _for_? + Jist for noth'n. Jist because we stood on our _rights_—that's what for. + But I lay you ain't a-goin' to threaten nobody any more, Jim Turner. + Put _up_ that pistol, Bill." + Bill says: + "I don't want to, Jake Packard. + I'm for killin' him—and didn't he kill old Hatfield jist the same way—and don't he deserve it?" + "But I don't _want_ him killed, and I've got my reasons for it." + "Bless yo' heart for them words, Jake Packard! + I'll never forgit you long's I live!" + says the man on the floor, sort of blubbering. + Packard didn't take no notice of that, but hung up his lantern on a nail and started towards where I was there in the dark, and motioned Bill to come. + I crawfished as fast as I could about two yards, but the boat slanted so that I couldn't make very good time; so to keep from getting run over and catched I crawled into a stateroom on the upper side. + The man came a-pawing along in the dark, and when Packard got to my stateroom, he says: + "Here—come in here." + And in he come, and Bill after him. + But before they got in I was up in the upper berth, cornered, and sorry I come. + Then they stood there, with their hands on the ledge of the berth, and talked. + I couldn't see them, but I could tell where they was by the whisky they'd been having. + I was glad I didn't drink whisky; but it wouldn't made much difference anyway, because most of the time they couldn't a treed me because I didn't breathe. + I was too scared. + And, besides, a body _couldn't_ breathe and hear such talk. + They talked low and earnest. + Bill wanted to kill Turner. + He says: + "He's said he'll tell, and he will. + If we was to give both our shares to him _now_ it wouldn't make no difference after the row and the way we've served him. + Shore's you're born, he'll turn State's evidence; now you hear _me_. + I'm for putting him out of his troubles." + "So'm I," says Packard, very quiet. + "Blame it, I'd sorter begun to think you wasn't. + Well, then, that's all right. + Le's go and do it." + "Hold on a minute; I hain't had my say yit. + You listen to me. + Shooting's good, but there's quieter ways if the thing's _got_ to be done. + But what I say is this: it ain't good sense to go court'n around after a halter if you can git at what you're up to in some way that's jist as good and at the same time don't bring you into no resks. + Ain't that so?" + "You bet it is. + But how you goin' to manage it this time?" + "Well, my idea is this: we'll rustle around and gather up whatever pickins we've overlooked in the staterooms, and shove for shore and hide the truck. + Then we'll wait. + Now I say it ain't a-goin' to be more'n two hours befo' this wrack breaks up and washes off down the river. + See? + He'll be drownded, and won't have nobody to blame for it but his own self. + I reckon that's a considerble sight better 'n killin' of him. + I'm unfavorable to killin' a man as long as you can git aroun' it; it ain't good sense, it ain't good morals. + Ain't I right?" + "Yes, I reck'n you are. + But s'pose she _don't_ break up and wash off?" + "Well, we can wait the two hours anyway and see, can't we?" + "All right, then; come along." + So they started, and I lit out, all in a cold sweat, and scrambled forward. + It was dark as pitch there; but I said, in a kind of a coarse whisper, "Jim!" + and he answered up, right at my elbow, with a sort of a moan, and I says: + "Quick, Jim, it ain't no time for fooling around and moaning; there's a gang of murderers in yonder, and if we don't hunt up their boat and set her drifting down the river so these fellows can't get away from the wreck there's one of 'em going to be in a bad fix. + But if we find their boat we can put _all_ of 'em in a bad fix—for the sheriff 'll get 'em. + Quick—hurry! + I'll hunt the labboard side, you hunt the stabboard. + You start at the raft, and—" + "Oh, my lordy, lordy! + _raf'_? + Dey ain' no raf' no mo'; she done broke loose en gone I—en here we is!" + CHAPTER XIII. + WELL, I catched my breath and most fainted. + Shut up on a wreck with such a gang as that! + But it warn't no time to be sentimentering. + We'd _got_ to find that boat now—had to have it for ourselves. + So we went a-quaking and shaking down the stabboard side, and slow work it was, too—seemed a week before we got to the stern. + No sign of a boat. + Jim said he didn't believe he could go any further—so scared he hadn't hardly any strength left, he said. + But I said, come on, if we get left on this wreck we are in a fix, sure. + So on we prowled again. + We struck for the stern of the texas, and found it, and then scrabbled along forwards on the skylight, hanging on from shutter to shutter, for the edge of the skylight was in the water. + When we got pretty close to the cross-hall door there was the skiff, sure enough! + I could just barely see her. + I felt ever so thankful. + In another second I would a been aboard of her, but just then the door opened. + One of the men stuck his head out only about a couple of foot from me, and I thought I was gone; but he jerked it in again, and says: + "Heave that blame lantern out o' sight, Bill!" + He flung a bag of something into the boat, and then got in himself and set down. + It was Packard. + Then Bill _he_ come out and got in. + Packard says, in a low voice: + "All ready—shove off!" + I couldn't hardly hang on to the shutters, I was so weak. + But Bill says: + "Hold on—'d you go through him?" + "No. + Didn't you?" + "No. + So he's got his share o' the cash yet." + "Well, then, come along; no use to take truck and leave money." + "Say, won't he suspicion what we're up to?" + "Maybe he won't. + But we got to have it anyway. + Come along." + So they got out and went in. + The door slammed to because it was on the careened side; and in a half second I was in the boat, and Jim come tumbling after me. + I out with my knife and cut the rope, and away we went! + We didn't touch an oar, and we didn't speak nor whisper, nor hardly even breathe. + We went gliding swift along, dead silent, past the tip of the paddle-box, and past the stern; then in a second or two more we was a hundred yards below the wreck, and the darkness soaked her up, every last sign of her, and we was safe, and knowed it. + When we was three or four hundred yards down-stream we see the lantern show like a little spark at the texas door for a second, and we knowed by that that the rascals had missed their boat, and was beginning to understand that they was in just as much trouble now as Jim Turner was. + Then Jim manned the oars, and we took out after our raft. + Now was the first time that I begun to worry about the men—I reckon I hadn't had time to before. + I begun to think how dreadful it was, even for murderers, to be in such a fix. + I says to myself, there ain't no telling but I might come to be a murderer myself yet, and then how would I like it? + So says I to Jim: + "The first light we see we'll land a hundred yards below it or above it, in a place where it's a good hiding-place for you and the skiff, and then I'll go and fix up some kind of a yarn, and get somebody to go for that gang and get them out of their scrape, so they can be hung when their time comes." + But that idea was a failure; for pretty soon it begun to storm again, and this time worse than ever. + The rain poured down, and never a light showed; everybody in bed, I reckon. + We boomed along down the river, watching for lights and watching for our raft. + After a long time the rain let up, but the clouds stayed, and the lightning kept whimpering, and by and by a flash showed us a black thing ahead, floating, and we made for it. + It was the raft, and mighty glad was we to get aboard of it again. + We seen a light now away down to the right, on shore. + So I said I would go for it. + The skiff was half full of plunder which that gang had stole there on the wreck. + We hustled it on to the raft in a pile, and I told Jim to float along down, and show a light when he judged he had gone about two mile, and keep it burning till I come; then I manned my oars and shoved for the light. + As I got down towards it three or four more showed—up on a hillside. + It was a village. + I closed in above the shore light, and laid on my oars and floated. + As I went by I see it was a lantern hanging on the jackstaff of a double-hull ferryboat. + I skimmed around for the watchman, a-wondering whereabouts he slept; and by and by I found him roosting on the bitts forward, with his head down between his knees. + I gave his shoulder two or three little shoves, and begun to cry. + He stirred up in a kind of a startlish way; but when he see it was only me he took a good gap and stretch, and then he says: + "Hello, what's up? + Don't cry, bub. + What's the trouble?" + I says: + "Pap, and mam, and sis, and—" + Then I broke down. + He says: + "Oh, dang it now, _don't_ take on so; we all has to have our troubles, and this 'n 'll come out all right. + What's the matter with 'em?" + "They're—they're—are you the watchman of the boat?" + "Yes," he says, kind of pretty-well-satisfied like. + "I'm the captain and the owner and the mate and the pilot and watchman and head deck-hand; and sometimes I'm the freight and passengers. + I ain't as rich as old Jim Hornback, and I can't be so blame' generous and good to Tom, Dick, and Harry as what he is, and slam around money the way he does; but I've told him a many a time 't I wouldn't trade places with him; for, says I, a sailor's life's the life for me, and I'm derned if _I'd_ live two mile out o' town, where there ain't nothing ever goin' on, not for all his spondulicks and as much more on top of it. + Says I—" + I broke in and says: + "They're in an awful peck of trouble, and—" + "_Who_ is?" + "Why, pap and mam and sis and Miss Hooker; and if you'd take your ferryboat and go up there—" + "Up where? + Where are they?" + "On the wreck." + "What wreck?" + "Why, there ain't but one." + "What, you don't mean the Walter Scott?" + "Yes." + "Good land! + what are they doin' _there_, for gracious sakes?" + "Well, they didn't go there a-purpose." + "I bet they didn't! + Why, great goodness, there ain't no chance for 'em if they don't git off mighty quick! + Why, how in the nation did they ever git into such a scrape?" + "Easy enough. + Miss Hooker was a-visiting up there to the town—" + "Yes, Booth's Landing—go on." + "She was a-visiting there at Booth's Landing, and just in the edge of the evening she started over with her nigger woman in the horse-ferry to stay all night at her friend's house, Miss What-you-may-call-her I disremember her name—and they lost their steering-oar, and swung around and went a-floating down, stern first, about two mile, and saddle-baggsed on the wreck, and the ferryman and the nigger woman and the horses was all lost, but Miss Hooker she made a grab and got aboard the wreck. + Well, about an hour after dark we come along down in our trading-scow, and it was so dark we didn't notice the wreck till we was right on it; and so _we_ saddle-baggsed; but all of us was saved but Bill Whipple—and oh, he _was_ the best cretur! + —I most wish 't it had been me, I do." + "My George! + It's the beatenest thing I ever struck. + And _then_ what did you all do?" + "Well, we hollered and took on, but it's so wide there we couldn't make nobody hear. + So pap said somebody got to get ashore and get help somehow. + I was the only one that could swim, so I made a dash for it, and Miss Hooker she said if I didn't strike help sooner, come here and hunt up her uncle, and he'd fix the thing. + I made the land about a mile below, and been fooling along ever since, trying to get people to do something, but they said, 'What, in such a night and such a current? + There ain't no sense in it; go for the steam ferry.' + Now if you'll go and—" + "By Jackson, I'd _like_ to, and, blame it, I don't know but I will; but who in the dingnation's a-going' to _pay_ for it? + Do you reckon your pap—" + "Why _that's_ all right. + Miss Hooker she tole me, _particular_, that her uncle Hornback—" + "Great guns! + is _he_ her uncle? + Looky here, you break for that light over yonder-way, and turn out west when you git there, and about a quarter of a mile out you'll come to the tavern; tell 'em to dart you out to Jim Hornback's, and he'll foot the bill. + And don't you fool around any, because he'll want to know the news. + Tell him I'll have his niece all safe before he can get to town. + Hump yourself, now; I'm a-going up around the corner here to roust out my engineer." + I struck for the light, but as soon as he turned the corner I went back and got into my skiff and bailed her out, and then pulled up shore in the easy water about six hundred yards, and tucked myself in among some woodboats; for I couldn't rest easy till I could see the ferryboat start. + But take it all around, I was feeling ruther comfortable on accounts of taking all this trouble for that gang, for not many would a done it. + I wished the widow knowed about it. + I judged she would be proud of me for helping these rapscallions, because rapscallions and dead beats is the kind the widow and good people takes the most interest in. + Well, before long here comes the wreck, dim and dusky, sliding along down! + A kind of cold shiver went through me, and then I struck out for her. + She was very deep, and I see in a minute there warn't much chance for anybody being alive in her. + I pulled all around her and hollered a little, but there wasn't any answer; all dead still. + I felt a little bit heavy-hearted about the gang, but not much, for I reckoned if they could stand it I could. + Then here comes the ferryboat; so I shoved for the middle of the river on a long down-stream slant; and when I judged I was out of eye-reach I laid on my oars, and looked back and see her go and smell around the wreck for Miss Hooker's remainders, because the captain would know her uncle Hornback would want them; and then pretty soon the ferryboat give it up and went for the shore, and I laid into my work and went a-booming down the river. + It did seem a powerful long time before Jim's light showed up; and when it did show it looked like it was a thousand mile off. + By the time I got there the sky was beginning to get a little gray in the east; so we struck for an island, and hid the raft, and sunk the skiff, and turned in and slept like dead people. + CHAPTER XIV. + BY and by, when we got up, we turned over the truck the gang had stole off of the wreck, and found boots, and blankets, and clothes, and all sorts of other things, and a lot of books, and a spyglass, and three boxes of seegars. + We hadn't ever been this rich before in neither of our lives. + The seegars was prime. + We laid off all the afternoon in the woods talking, and me reading the books, and having a general good time. + I told Jim all about what happened inside the wreck and at the ferryboat, and I said these kinds of things was adventures; but he said he didn't want no more adventures. + He said that when I went in the texas and he crawled back to get on the raft and found her gone he nearly died, because he judged it was all up with _him_ anyway it could be fixed; for if he didn't get saved he would get drownded; and if he did get saved, whoever saved him would send him back home so as to get the reward, and then Miss Watson would sell him South, sure. + Well, he was right; he was most always right; he had an uncommon level head for a nigger. + I read considerable to Jim about kings and dukes and earls and such, and how gaudy they dressed, and how much style they put on, and called each other your majesty, and your grace, and your lordship, and so on, 'stead of mister; and Jim's eyes bugged out, and he was interested. + He says: + "I didn' know dey was so many un um. + I hain't hearn 'bout none un um, skasely, but ole King Sollermun, onless you counts dem kings dat's in a pack er k'yards. + How much do a king git?" + "Get?" + I says; "why, they get a thousand dollars a month if they want it; they can have just as much as they want; everything belongs to them." + "_Ain'_ dat gay? + En what dey got to do, Huck?" + "_They_ don't do nothing! + Why, how you talk! + They just set around." + "No; is dat so?" + "Of course it is. + They just set around—except, maybe, when there's a war; then they go to the war. + But other times they just lazy around; or go hawking—just hawking and sp—Sh! + —d' you hear a noise?" + We skipped out and looked; but it warn't nothing but the flutter of a steamboat's wheel away down, coming around the point; so we come back. + "Yes," says I, "and other times, when things is dull, they fuss with the parlyment; and if everybody don't go just so he whacks their heads off. + But mostly they hang round the harem." + "Roun' de which?" + "Harem." + "What's de harem?" + "The place where he keeps his wives. + Don't you know about the harem? + Solomon had one; he had about a million wives." + "Why, yes, dat's so; I—I'd done forgot it. + A harem's a bo'd'n-house, I reck'n. Mos' likely dey has rackety times in de nussery. + En I reck'n de wives quarrels considable; en dat 'crease de racket. + Yit dey say Sollermun de wises' man dat ever live'. + I doan' take no stock in dat. + Bekase why: would a wise man want to live in de mids' er sich a blim-blammin' all de time? + No—'deed he wouldn't. + A wise man 'ud take en buil' a biler-factry; en den he could shet _down_ de biler-factry when he want to res'." + "Well, but he _was_ the wisest man, anyway; because the widow she told me so, her own self." + "I doan k'yer what de widder say, he _warn't_ no wise man nuther. + He had some er de dad-fetchedes' ways I ever see. + Does you know 'bout dat chile dat he 'uz gwyne to chop in two?" + "Yes, the widow told me all about it." + "_Well_, den! + Warn' dat de beatenes' notion in de worl'? + You jes' take en look at it a minute. + Dah's de stump, dah—dat's one er de women; heah's you—dat's de yuther one; I's Sollermun; en dish yer dollar bill's de chile. + Bofe un you claims it. + What does I do? + Does I shin aroun' mongs' de neighbors en fine out which un you de bill _do_ b'long to, en han' it over to de right one, all safe en soun', de way dat anybody dat had any gumption would? + No; I take en whack de bill in _two_, en give half un it to you, en de yuther half to de yuther woman. + Dat's de way Sollermun was gwyne to do wid de chile. + Now I want to ast you: what's de use er dat half a bill? + —can't buy noth'n wid it. + En what use is a half a chile? + I wouldn' give a dern for a million un um." + "But hang it, Jim, you've clean missed the point—blame it, you've missed it a thousand mile." + "Who? + Me? + Go 'long. + Doan' talk to me 'bout yo' pints. + I reck'n I knows sense when I sees it; en dey ain' no sense in sich doin's as dat. + De 'spute warn't 'bout a half a chile, de 'spute was 'bout a whole chile; en de man dat think he kin settle a 'spute 'bout a whole chile wid a half a chile doan' know enough to come in out'n de rain. + Doan' talk to me 'bout Sollermun, Huck, I knows him by de back." + "But I tell you you don't get the point." + "Blame de point! + I reck'n I knows what I knows. + En mine you, de _real_ pint is down furder—it's down deeper. + It lays in de way Sollermun was raised. + You take a man dat's got on'y one or two chillen; is dat man gwyne to be waseful o' chillen? + No, he ain't; he can't 'ford it. + _He_ know how to value 'em. + But you take a man dat's got 'bout five million chillen runnin' roun' de house, en it's diffunt. + _He_ as soon chop a chile in two as a cat. + Dey's plenty mo'. + A chile er two, mo' er less, warn't no consekens to Sollermun, dad fatch him!" + I never see such a nigger. + If he got a notion in his head once, there warn't no getting it out again. + He was the most down on Solomon of any nigger I ever see. + So I went to talking about other kings, and let Solomon slide. + I told about Louis Sixteenth that got his head cut off in France long time ago; and about his little boy the dolphin, that would a been a king, but they took and shut him up in jail, and some say he died there. + "Po' little chap." + "But some says he got out and got away, and come to America." + "Dat's good! + But he'll be pooty lonesome—dey ain' no kings here, is dey, Huck?" + "No." + "Den he cain't git no situation. + What he gwyne to do?" + "Well, I don't know. + Some of them gets on the police, and some of them learns people how to talk French." + "Why, Huck, doan' de French people talk de same way we does?" + "_No_, Jim; you couldn't understand a word they said—not a single word." + "Well, now, I be ding-busted! + How do dat come?" + "I don't know; but it's so. + I got some of their jabber out of a book. + S'pose a man was to come to you and say Polly-voo-franzy—what would you think?" + "I wouldn' think nuff'n; I'd take en bust him over de head—dat is, if he warn't white. + I wouldn't 'low no nigger to call me dat." + "Shucks, it ain't calling you anything. + It's only saying, do you know how to talk French?" + "Well, den, why couldn't he _say_ it?" + "Why, he _is_ a-saying it. + That's a Frenchman's _way_ of saying it." + "Well, it's a blame ridicklous way, en I doan' want to hear no mo' 'bout it. + Dey ain' no sense in it." + "Looky here, Jim; does a cat talk like we do?" + "No, a cat don't." + "Well, does a cow?" + "No, a cow don't, nuther." + "Does a cat talk like a cow, or a cow talk like a cat?" + "No, dey don't." + "It's natural and right for 'em to talk different from each other, ain't it?" + "Course." + "And ain't it natural and right for a cat and a cow to talk different from _us_?" + "Why, mos' sholy it is." + "Well, then, why ain't it natural and right for a _Frenchman_ to talk different from us? + You answer me that." + "Is a cat a man, Huck?" + "No." + "Well, den, dey ain't no sense in a cat talkin' like a man. + Is a cow a man? + —er is a cow a cat?" + "No, she ain't either of them." + "Well, den, she ain't got no business to talk like either one er the yuther of 'em. + Is a Frenchman a man?" + "Yes." + "_Well_, den! + Dad blame it, why doan' he _talk_ like a man? + You answer me _dat_!" + I see it warn't no use wasting words—you can't learn a nigger to argue. + So I quit. + CHAPTER XV. + WE judged that three nights more would fetch us to Cairo, at the bottom of Illinois, where the Ohio River comes in, and that was what we was after. + We would sell the raft and get on a steamboat and go way up the Ohio amongst the free States, and then be out of trouble. + Well, the second night a fog begun to come on, and we made for a towhead to tie to, for it wouldn't do to try to run in a fog; but when I paddled ahead in the canoe, with the line to make fast, there warn't anything but little saplings to tie to. + I passed the line around one of them right on the edge of the cut bank, but there was a stiff current, and the raft come booming down so lively she tore it out by the roots and away she went. + I see the fog closing down, and it made me so sick and scared I couldn't budge for most a half a minute it seemed to me—and then there warn't no raft in sight; you couldn't see twenty yards. + I jumped into the canoe and run back to the stern, and grabbed the paddle and set her back a stroke. + But she didn't come. + I was in such a hurry I hadn't untied her. + I got up and tried to untie her, but I was so excited my hands shook so I couldn't hardly do anything with them. + As soon as I got started I took out after the raft, hot and heavy, right down the towhead. + That was all right as far as it went, but the towhead warn't sixty yards long, and the minute I flew by the foot of it I shot out into the solid white fog, and hadn't no more idea which way I was going than a dead man. + Thinks I, it won't do to paddle; first I know I'll run into the bank or a towhead or something; I got to set still and float, and yet it's mighty fidgety business to have to hold your hands still at such a time. + I whooped and listened. + Away down there somewheres I hears a small whoop, and up comes my spirits. + I went tearing after it, listening sharp to hear it again. + The next time it come I see I warn't heading for it, but heading away to the right of it. + And the next time I was heading away to the left of it—and not gaining on it much either, for I was flying around, this way and that and t'other, but it was going straight ahead all the time. + I did wish the fool would think to beat a tin pan, and beat it all the time, but he never did, and it was the still places between the whoops that was making the trouble for me. + Well, I fought along, and directly I hears the whoop _behind_ me. + I was tangled good now. + That was somebody else's whoop, or else I was turned around. + I throwed the paddle down. + I heard the whoop again; it was behind me yet, but in a different place; it kept coming, and kept changing its place, and I kept answering, till by and by it was in front of me again, and I knowed the current had swung the canoe's head down-stream, and I was all right if that was Jim and not some other raftsman hollering. + I couldn't tell nothing about voices in a fog, for nothing don't look natural nor sound natural in a fog. + The whooping went on, and in about a minute I come a-booming down on a cut bank with smoky ghosts of big trees on it, and the current throwed me off to the left and shot by, amongst a lot of snags that fairly roared, the currrent was tearing by them so swift. + In another second or two it was solid white and still again. + I set perfectly still then, listening to my heart thump, and I reckon I didn't draw a breath while it thumped a hundred. + I just give up then. + I knowed what the matter was. + That cut bank was an island, and Jim had gone down t'other side of it. + It warn't no towhead that you could float by in ten minutes. + It had the big timber of a regular island; it might be five or six miles long and more than half a mile wide. + I kept quiet, with my ears cocked, about fifteen minutes, I reckon. + I was floating along, of course, four or five miles an hour; but you don't ever think of that. + No, you _feel_ like you are laying dead still on the water; and if a little glimpse of a snag slips by you don't think to yourself how fast _you're_ going, but you catch your breath and think, my! + how that snag's tearing along. + If you think it ain't dismal and lonesome out in a fog that way by yourself in the night, you try it once—you'll see. + Next, for about a half an hour, I whoops now and then; at last I hears the answer a long ways off, and tries to follow it, but I couldn't do it, and directly I judged I'd got into a nest of towheads, for I had little dim glimpses of them on both sides of me—sometimes just a narrow channel between, and some that I couldn't see I knowed was there because I'd hear the wash of the current against the old dead brush and trash that hung over the banks. + Well, I warn't long loosing the whoops down amongst the towheads; and I only tried to chase them a little while, anyway, because it was worse than chasing a Jack-o'-lantern. + You never knowed a sound dodge around so, and swap places so quick and so much. + I had to claw away from the bank pretty lively four or five times, to keep from knocking the islands out of the river; and so I judged the raft must be butting into the bank every now and then, or else it would get further ahead and clear out of hearing—it was floating a little faster than what I was. + Well, I seemed to be in the open river again by and by, but I couldn't hear no sign of a whoop nowheres. + I reckoned Jim had fetched up on a snag, maybe, and it was all up with him. + I was good and tired, so I laid down in the canoe and said I wouldn't bother no more. + I didn't want to go to sleep, of course; but I was so sleepy I couldn't help it; so I thought I would take jest one little cat-nap. + But I reckon it was more than a cat-nap, for when I waked up the stars was shining bright, the fog was all gone, and I was spinning down a big bend stern first. + First I didn't know where I was; I thought I was dreaming; and when things began to come back to me they seemed to come up dim out of last week. + It was a monstrous big river here, with the tallest and the thickest kind of timber on both banks; just a solid wall, as well as I could see by the stars. + I looked away down-stream, and seen a black speck on the water. + I took after it; but when I got to it it warn't nothing but a couple of sawlogs made fast together. + Then I see another speck, and chased that; then another, and this time I was right. + It was the raft. + When I got to it Jim was setting there with his head down between his knees, asleep, with his right arm hanging over the steering-oar. + The other oar was smashed off, and the raft was littered up with leaves and branches and dirt. + So she'd had a rough time. + I made fast and laid down under Jim's nose on the raft, and began to gap, and stretch my fists out against Jim, and says: + "Hello, Jim, have I been asleep? + Why didn't you stir me up?" + "Goodness gracious, is dat you, Huck? + En you ain' dead—you ain' drownded—you's back agin? + It's too good for true, honey, it's too good for true. + Lemme look at you chile, lemme feel o' you. + No, you ain' dead! + you's back agin, 'live en soun', jis de same ole Huck—de same ole Huck, thanks to goodness!" + "What's the matter with you, Jim? + You been a-drinking?" + "Drinkin'? + Has I ben a-drinkin'? + Has I had a chance to be a-drinkin'?" + "Well, then, what makes you talk so wild?" + "How does I talk wild?" + "_How_? + Why, hain't you been talking about my coming back, and all that stuff, as if I'd been gone away?" + "Huck—Huck Finn, you look me in de eye; look me in de eye. + _Hain't_ you ben gone away?" + "Gone away? + Why, what in the nation do you mean? + I hain't been gone anywheres. + Where would I go to?" + "Well, looky here, boss, dey's sumf'n wrong, dey is. + Is I _me_, or who _is_ I? + Is I heah, or whah _is_ I? + Now dat's what I wants to know." + "Well, I think you're here, plain enough, but I think you're a tangle-headed old fool, Jim." + "I is, is I? + Well, you answer me dis: Didn't you tote out de line in de canoe fer to make fas' to de tow-head?" + "No, I didn't. + What tow-head? + I hain't see no tow-head." + "You hain't seen no towhead? + Looky here, didn't de line pull loose en de raf' go a-hummin' down de river, en leave you en de canoe behine in de fog?" + "What fog?" + "Why, de fog! + —de fog dat's been aroun' all night. + En didn't you whoop, en didn't I whoop, tell we got mix' up in de islands en one un us got los' en t'other one was jis' as good as los', 'kase he didn' know whah he wuz? + En didn't I bust up agin a lot er dem islands en have a turrible time en mos' git drownded? + Now ain' dat so, boss—ain't it so? + You answer me dat." + "Well, this is too many for me, Jim. + I hain't seen no fog, nor no islands, nor no troubles, nor nothing. + I been setting here talking with you all night till you went to sleep about ten minutes ago, and I reckon I done the same. + You couldn't a got drunk in that time, so of course you've been dreaming." + "Dad fetch it, how is I gwyne to dream all dat in ten minutes?" + "Well, hang it all, you did dream it, because there didn't any of it happen." + "But, Huck, it's all jis' as plain to me as—" + "It don't make no difference how plain it is; there ain't nothing in it. + I know, because I've been here all the time." + Jim didn't say nothing for about five minutes, but set there studying over it. + Then he says: + "Well, den, I reck'n I did dream it, Huck; but dog my cats ef it ain't de powerfullest dream I ever see. + En I hain't ever had no dream b'fo' dat's tired me like dis one." + "Oh, well, that's all right, because a dream does tire a body like everything sometimes. + But this one was a staving dream; tell me all about it, Jim." + So Jim went to work and told me the whole thing right through, just as it happened, only he painted it up considerable. + Then he said he must start in and "'terpret" it, because it was sent for a warning. + He said the first towhead stood for a man that would try to do us some good, but the current was another man that would get us away from him. + The whoops was warnings that would come to us every now and then, and if we didn't try hard to make out to understand them they'd just take us into bad luck, 'stead of keeping us out of it. + The lot of towheads was troubles we was going to get into with quarrelsome people and all kinds of mean folks, but if we minded our business and didn't talk back and aggravate them, we would pull through and get out of the fog and into the big clear river, which was the free States, and wouldn't have no more trouble. + It had clouded up pretty dark just after I got on to the raft, but it was clearing up again now. + "Oh, well, that's all interpreted well enough as far as it goes, Jim," I says; "but what does _these_ things stand for?" + It was the leaves and rubbish on the raft and the smashed oar. + You could see them first-rate now. + Jim looked at the trash, and then looked at me, and back at the trash again. + He had got the dream fixed so strong in his head that he couldn't seem to shake it loose and get the facts back into its place again right away. + But when he did get the thing straightened around he looked at me steady without ever smiling, and says: + "What do dey stan' for? + I'se gwyne to tell you. + When I got all wore out wid work, en wid de callin' for you, en went to sleep, my heart wuz mos' broke bekase you wuz los', en I didn' k'yer no' mo' what become er me en de raf'. + En when I wake up en fine you back agin, all safe en soun', de tears come, en I could a got down on my knees en kiss yo' foot, I's so thankful. + En all you wuz thinkin' 'bout wuz how you could make a fool uv ole Jim wid a lie. + Dat truck dah is _trash_; en trash is what people is dat puts dirt on de head er dey fren's en makes 'em ashamed." + Then he got up slow and walked to the wigwam, and went in there without saying anything but that. + But that was enough. + It made me feel so mean I could almost kissed _his_ foot to get him to take it back. + It was fifteen minutes before I could work myself up to go and humble myself to a nigger; but I done it, and I warn't ever sorry for it afterwards, neither. + I didn't do him no more mean tricks, and I wouldn't done that one if I'd a knowed it would make him feel that way. + + diff --git a/Huckleberry/Huckleberry/UYLAppDelegate.h b/Huckleberry/Huckleberry/UYLAppDelegate.h new file mode 100644 index 0000000..ee69935 --- /dev/null +++ b/Huckleberry/Huckleberry/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Huckleberry/Huckleberry/UYLAppDelegate.m b/Huckleberry/Huckleberry/UYLAppDelegate.m new file mode 100644 index 0000000..e06f38e --- /dev/null +++ b/Huckleberry/Huckleberry/UYLAppDelegate.m @@ -0,0 +1,38 @@ +// +// UYLAppDelegate.m +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +@end diff --git a/Huckleberry/Huckleberry/UYLTableViewController.h b/Huckleberry/Huckleberry/UYLTableViewController.h new file mode 100644 index 0000000..5a1b9e7 --- /dev/null +++ b/Huckleberry/Huckleberry/UYLTableViewController.h @@ -0,0 +1,38 @@ +// +// UYLTableViewController.h +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTableViewController : UITableViewController + +@end diff --git a/Huckleberry/Huckleberry/UYLTableViewController.m b/Huckleberry/Huckleberry/UYLTableViewController.m new file mode 100644 index 0000000..0ccbfcf --- /dev/null +++ b/Huckleberry/Huckleberry/UYLTableViewController.m @@ -0,0 +1,147 @@ +// +// UYLTableViewController.m +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLTableViewController.h" +#import "UYLTextCell.h" + +@interface UYLTableViewController () + +@property (nonatomic, strong) NSArray *sourceData; +@property (nonatomic, strong) UYLTextCell *prototypeCell; + +@end + +@implementation UYLTableViewController + +static NSString *UYLCellIdentifier = @"UYLTextCell"; + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +- (NSArray *)sourceData +{ + if (!_sourceData) + { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"SourceData" ofType:@"plist"]; + _sourceData = [NSArray arrayWithContentsOfFile:filePath]; + } + return _sourceData; +} + +- (UYLTextCell *)prototypeCell +{ + if (!_prototypeCell) + { + _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:UYLCellIdentifier]; + } + return _prototypeCell; +} + +#pragma mark - +#pragma mark === View Life Cycle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification object:nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIContentSizeCategoryDidChangeNotification + object:nil]; +} + +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self.tableView reloadData]; +} + +#pragma mark - +#pragma mark === UITableViewDataSource === +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.sourceData count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:UYLCellIdentifier forIndexPath:indexPath]; + [self configureCell:cell forRowAtIndexPath:indexPath]; + return cell; +} + +- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath +{ + if ([cell isKindOfClass:[UYLTextCell class]]) + { + UYLTextCell *textCell = (UYLTextCell *)cell; + textCell.numberLabel.text = [NSString stringWithFormat:@"Line %ld",(long)indexPath.row+1]; + textCell.numberLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; + textCell.lineLabel.text = [self.sourceData objectAtIndex:indexPath.row]; + textCell.lineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + } +} + +#pragma mark - +#pragma mark === UITableViewDelegate === +#pragma mark - + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath]; + + // Need to set the width of the prototype cell to the width of the table view + // as this will change when the device is rotated. + + self.prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds)); + + [self.prototypeCell layoutIfNeeded]; + + CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + return size.height+1; +} + +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return UITableViewAutomaticDimension; +} + +@end diff --git a/Huckleberry/Huckleberry/UYLTextCell.h b/Huckleberry/Huckleberry/UYLTextCell.h new file mode 100644 index 0000000..02de101 --- /dev/null +++ b/Huckleberry/Huckleberry/UYLTextCell.h @@ -0,0 +1,41 @@ +// +// UYLTextCell.h +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTextCell : UITableViewCell + +@property (weak, nonatomic) IBOutlet UILabel *numberLabel; +@property (weak, nonatomic) IBOutlet UILabel *lineLabel; + +@end \ No newline at end of file diff --git a/Huckleberry/Huckleberry/UYLTextCell.m b/Huckleberry/Huckleberry/UYLTextCell.m new file mode 100644 index 0000000..b9564bd --- /dev/null +++ b/Huckleberry/Huckleberry/UYLTextCell.m @@ -0,0 +1,65 @@ +// +// UYLTextCell.m +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLTextCell.h" + +@implementation UYLTextCell + +- (id)debugQuickLookObject +{ + // NSString *result = [NSString stringWithFormat:@"%@: %@",self.numberLabel.text,self.lineLabel.text]; + + NSAttributedString *cr = [[NSAttributedString alloc] initWithString:@"\n"]; + NSMutableAttributedString *result = [[NSMutableAttributedString alloc] initWithAttributedString:self.numberLabel.attributedText]; + [result appendAttributedString:cr]; + [result appendAttributedString:self.lineLabel.attributedText]; + return result; +} + +// Need to implement layoutSubiews and set the preferred max layout width of the multi-line label or +// the cell height does not get correctly calculated when the device changes orientation. +// +// Credit to this GitHub example project and StackOverflow answer for providing the missing details: +// +// https://github.com/smileyborg/TableViewCellWithAutoLayout +// http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + [self.contentView layoutIfNeeded]; + self.lineLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.lineLabel.frame); +} + +@end \ No newline at end of file diff --git a/Huckleberry/Huckleberry/en.lproj/InfoPlist.strings b/Huckleberry/Huckleberry/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Huckleberry/Huckleberry/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Huckleberry/Huckleberry/main.m b/Huckleberry/Huckleberry/main.m new file mode 100644 index 0000000..65d2d22 --- /dev/null +++ b/Huckleberry/Huckleberry/main.m @@ -0,0 +1,43 @@ +// +// main.m +// Huckleberry +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/Huckleberry/README.md b/Huckleberry/README.md new file mode 100644 index 0000000..cd6fab6 --- /dev/null +++ b/Huckleberry/README.md @@ -0,0 +1,32 @@ +# Huckleberry + +**This project is of historical interest only. I recommend using a self-sizing table view instead of the prototype cell approach used in this project.** + +## Auto layout table view cells with varying row heights + +Example of how to implement table view cells with varying row heights +using auto layout constraints and a dummy prototype cell. + +The fix for device rotation came from this GitHub example project: + +https://github.com/smileyborg/TableViewCellWithAutoLayout + +The source data for the table view is taken from the first 15 chapters +of Huckleberry Finn as found on Project Gutenberg. This gives nearly +2000 rows of data. + +For further details see the following blog post: + ++ [Table View Cells with Varying Row Heights](https://useyourloaf.com/blog/table-view-cells-with-varying-row-heights/) + +The custom table view class (UYLTextCell) includes an implementation +of debugQuickLookObject to support Quick Look view of the cell in the +Xcode debugger (requires Xcode 5.1). See the following post for details: + ++ [Xcode Debugger Quick Look](https://useyourloaf.com/blog/xcode-debugger-quick-look/) + +## History + +Version 1.2 17 March 2014 Fix device rotation +Version 1.1 12 March 2014 Added Quick Look Debug +Version 1.0 14 February 2014 Initial version. diff --git a/KeyCommand/KeyCommand.xcodeproj/project.pbxproj b/KeyCommand/KeyCommand.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bef861b --- /dev/null +++ b/KeyCommand/KeyCommand.xcodeproj/project.pbxproj @@ -0,0 +1,527 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 532005211DD516C300EEFEE6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 532005201DD516C300EEFEE6 /* main.m */; }; + 532005241DD516C300EEFEE6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 532005231DD516C300EEFEE6 /* AppDelegate.m */; }; + 532005361DD517AF00EEFEE6 /* OptionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532005351DD517AF00EEFEE6 /* OptionViewController.m */; }; + 532005391DD517C000EEFEE6 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532005381DD517C000EEFEE6 /* DetailViewController.m */; }; + 5320053C1DD518F900EEFEE6 /* UYLPriority.m in Sources */ = {isa = PBXBuildFile; fileRef = 5320053B1DD518F900EEFEE6 /* UYLPriority.m */; }; + 5334D07B1DD3B6250032CB00 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5334D07A1DD3B6250032CB00 /* AppDelegate.swift */; }; + 5334D0801DD3B6250032CB00 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5334D07E1DD3B6250032CB00 /* Main.storyboard */; }; + 5334D0821DD3B6250032CB00 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5334D0811DD3B6250032CB00 /* Assets.xcassets */; }; + 5334D0851DD3B6250032CB00 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5334D0831DD3B6250032CB00 /* LaunchScreen.storyboard */; }; + 5334D08D1DD3B82E0032CB00 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5334D08C1DD3B82E0032CB00 /* DetailViewController.swift */; }; + 5334D08F1DD3B8630032CB00 /* OptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5334D08E1DD3B8630032CB00 /* OptionViewController.swift */; }; + 5334D0911DD3BAC80032CB00 /* UYLPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5334D0901DD3BAC80032CB00 /* UYLPriority.swift */; }; + 5334D0931DD3BDAB0032CB00 /* SegueHandlerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5334D0921DD3BDAB0032CB00 /* SegueHandlerType.swift */; }; + 53376AB41DD77247002C287F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5334D0811DD3B6250032CB00 /* Assets.xcassets */; }; + 53376AB61DD772CB002C287F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5334D0831DD3B6250032CB00 /* LaunchScreen.storyboard */; }; + 53376AB81DD77736002C287F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 532005281DD516C300EEFEE6 /* Main.storyboard */; }; + 53376ABC1DD7789F002C287F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53376ABF1DD7789F002C287F /* Localizable.strings */; }; + 53376ABD1DD7789F002C287F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53376ABF1DD7789F002C287F /* Localizable.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5320051D1DD516C300EEFEE6 /* KeyCommandObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeyCommandObjC.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 532005201DD516C300EEFEE6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 532005221DD516C300EEFEE6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 532005231DD516C300EEFEE6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 532005291DD516C300EEFEE6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 532005301DD516C300EEFEE6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 532005341DD517AF00EEFEE6 /* OptionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionViewController.h; sourceTree = ""; }; + 532005351DD517AF00EEFEE6 /* OptionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OptionViewController.m; sourceTree = ""; }; + 532005371DD517C000EEFEE6 /* DetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; + 532005381DD517C000EEFEE6 /* DetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; + 5320053A1DD518F900EEFEE6 /* UYLPriority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLPriority.h; sourceTree = ""; }; + 5320053B1DD518F900EEFEE6 /* UYLPriority.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLPriority.m; sourceTree = ""; }; + 5334D0771DD3B6250032CB00 /* KeyCommand.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeyCommand.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5334D07A1DD3B6250032CB00 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5334D07F1DD3B6250032CB00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5334D0811DD3B6250032CB00 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = KeyCommand/Assets.xcassets; sourceTree = ""; }; + 5334D0841DD3B6250032CB00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5334D0861DD3B6250032CB00 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5334D08C1DD3B82E0032CB00 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 5334D08E1DD3B8630032CB00 /* OptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionViewController.swift; sourceTree = ""; }; + 5334D0901DD3BAC80032CB00 /* UYLPriority.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UYLPriority.swift; sourceTree = ""; }; + 5334D0921DD3BDAB0032CB00 /* SegueHandlerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegueHandlerType.swift; sourceTree = ""; }; + 53376ABE1DD7789F002C287F /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; + 53376AC01DD77B74002C287F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5320051A1DD516C300EEFEE6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5334D0741DD3B6250032CB00 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5320051E1DD516C300EEFEE6 /* KeyCommandObjC */ = { + isa = PBXGroup; + children = ( + 532005221DD516C300EEFEE6 /* AppDelegate.h */, + 532005231DD516C300EEFEE6 /* AppDelegate.m */, + 532005341DD517AF00EEFEE6 /* OptionViewController.h */, + 532005351DD517AF00EEFEE6 /* OptionViewController.m */, + 532005371DD517C000EEFEE6 /* DetailViewController.h */, + 532005381DD517C000EEFEE6 /* DetailViewController.m */, + 5320053A1DD518F900EEFEE6 /* UYLPriority.h */, + 5320053B1DD518F900EEFEE6 /* UYLPriority.m */, + 532005281DD516C300EEFEE6 /* Main.storyboard */, + 532005301DD516C300EEFEE6 /* Info.plist */, + 5320051F1DD516C300EEFEE6 /* Supporting Files */, + ); + path = KeyCommandObjC; + sourceTree = ""; + }; + 5320051F1DD516C300EEFEE6 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 532005201DD516C300EEFEE6 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 5334D06E1DD3B6250032CB00 = { + isa = PBXGroup; + children = ( + 53376AC01DD77B74002C287F /* README.md */, + 53376AB51DD77255002C287F /* Shared Resources */, + 5334D0791DD3B6250032CB00 /* KeyCommand */, + 5320051E1DD516C300EEFEE6 /* KeyCommandObjC */, + 5334D0781DD3B6250032CB00 /* Products */, + ); + sourceTree = ""; + }; + 5334D0781DD3B6250032CB00 /* Products */ = { + isa = PBXGroup; + children = ( + 5334D0771DD3B6250032CB00 /* KeyCommand.app */, + 5320051D1DD516C300EEFEE6 /* KeyCommandObjC.app */, + ); + name = Products; + sourceTree = ""; + }; + 5334D0791DD3B6250032CB00 /* KeyCommand */ = { + isa = PBXGroup; + children = ( + 5334D08E1DD3B8630032CB00 /* OptionViewController.swift */, + 5334D08C1DD3B82E0032CB00 /* DetailViewController.swift */, + 5334D07A1DD3B6250032CB00 /* AppDelegate.swift */, + 5334D07E1DD3B6250032CB00 /* Main.storyboard */, + 5334D0861DD3B6250032CB00 /* Info.plist */, + 5334D0901DD3BAC80032CB00 /* UYLPriority.swift */, + 5334D0921DD3BDAB0032CB00 /* SegueHandlerType.swift */, + ); + path = KeyCommand; + sourceTree = ""; + }; + 53376AB51DD77255002C287F /* Shared Resources */ = { + isa = PBXGroup; + children = ( + 5334D0811DD3B6250032CB00 /* Assets.xcassets */, + 5334D0831DD3B6250032CB00 /* LaunchScreen.storyboard */, + 53376ABF1DD7789F002C287F /* Localizable.strings */, + ); + name = "Shared Resources"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5320051C1DD516C300EEFEE6 /* KeyCommandObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 532005331DD516C300EEFEE6 /* Build configuration list for PBXNativeTarget "KeyCommandObjC" */; + buildPhases = ( + 532005191DD516C300EEFEE6 /* Sources */, + 5320051A1DD516C300EEFEE6 /* Frameworks */, + 5320051B1DD516C300EEFEE6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeyCommandObjC; + productName = KeyCommandObjC; + productReference = 5320051D1DD516C300EEFEE6 /* KeyCommandObjC.app */; + productType = "com.apple.product-type.application"; + }; + 5334D0761DD3B6250032CB00 /* KeyCommand */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5334D0891DD3B6250032CB00 /* Build configuration list for PBXNativeTarget "KeyCommand" */; + buildPhases = ( + 5334D0731DD3B6250032CB00 /* Sources */, + 5334D0741DD3B6250032CB00 /* Frameworks */, + 5334D0751DD3B6250032CB00 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeyCommand; + productName = KeyCommand; + productReference = 5334D0771DD3B6250032CB00 /* KeyCommand.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5334D06F1DD3B6250032CB00 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5320051C1DD516C300EEFEE6 = { + CreatedOnToolsVersion = 8.1; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + 5334D0761DD3B6250032CB00 = { + CreatedOnToolsVersion = 8.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 5334D0721DD3B6250032CB00 /* Build configuration list for PBXProject "KeyCommand" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5334D06E1DD3B6250032CB00; + productRefGroup = 5334D0781DD3B6250032CB00 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5334D0761DD3B6250032CB00 /* KeyCommand */, + 5320051C1DD516C300EEFEE6 /* KeyCommandObjC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5320051B1DD516C300EEFEE6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53376AB81DD77736002C287F /* Main.storyboard in Resources */, + 53376ABD1DD7789F002C287F /* Localizable.strings in Resources */, + 53376AB61DD772CB002C287F /* LaunchScreen.storyboard in Resources */, + 53376AB41DD77247002C287F /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5334D0751DD3B6250032CB00 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5334D0851DD3B6250032CB00 /* LaunchScreen.storyboard in Resources */, + 53376ABC1DD7789F002C287F /* Localizable.strings in Resources */, + 5334D0821DD3B6250032CB00 /* Assets.xcassets in Resources */, + 5334D0801DD3B6250032CB00 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 532005191DD516C300EEFEE6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 532005361DD517AF00EEFEE6 /* OptionViewController.m in Sources */, + 5320053C1DD518F900EEFEE6 /* UYLPriority.m in Sources */, + 532005241DD516C300EEFEE6 /* AppDelegate.m in Sources */, + 532005211DD516C300EEFEE6 /* main.m in Sources */, + 532005391DD517C000EEFEE6 /* DetailViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5334D0731DD3B6250032CB00 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5334D07B1DD3B6250032CB00 /* AppDelegate.swift in Sources */, + 5334D0911DD3BAC80032CB00 /* UYLPriority.swift in Sources */, + 5334D08D1DD3B82E0032CB00 /* DetailViewController.swift in Sources */, + 5334D0931DD3BDAB0032CB00 /* SegueHandlerType.swift in Sources */, + 5334D08F1DD3B8630032CB00 /* OptionViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 532005281DD516C300EEFEE6 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 532005291DD516C300EEFEE6 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5334D07E1DD3B6250032CB00 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5334D07F1DD3B6250032CB00 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5334D0831DD3B6250032CB00 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5334D0841DD3B6250032CB00 /* Base */, + ); + name = LaunchScreen.storyboard; + path = KeyCommand; + sourceTree = ""; + }; + 53376ABF1DD7789F002C287F /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 53376ABE1DD7789F002C287F /* Base */, + ); + name = Localizable.strings; + path = KeyCommand; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 532005311DD516C300EEFEE6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = KeyCommandObjC/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.KeyCommandObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 532005321DD516C300EEFEE6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = KeyCommandObjC/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.KeyCommandObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 5334D0871DD3B6250032CB00 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 2; + }; + name = Debug; + }; + 5334D0881DD3B6250032CB00 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = 2; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5334D08A1DD3B6250032CB00 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = KeyCommand/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.2; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.KeyCommand; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5334D08B1DD3B6250032CB00 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = KeyCommand/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.2; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.KeyCommand; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 532005331DD516C300EEFEE6 /* Build configuration list for PBXNativeTarget "KeyCommandObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 532005311DD516C300EEFEE6 /* Debug */, + 532005321DD516C300EEFEE6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5334D0721DD3B6250032CB00 /* Build configuration list for PBXProject "KeyCommand" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5334D0871DD3B6250032CB00 /* Debug */, + 5334D0881DD3B6250032CB00 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5334D0891DD3B6250032CB00 /* Build configuration list for PBXNativeTarget "KeyCommand" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5334D08A1DD3B6250032CB00 /* Debug */, + 5334D08B1DD3B6250032CB00 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5334D06F1DD3B6250032CB00 /* Project object */; +} diff --git a/KeyCommand/KeyCommand/AppDelegate.swift b/KeyCommand/KeyCommand/AppDelegate.swift new file mode 100644 index 0000000..f665964 --- /dev/null +++ b/KeyCommand/KeyCommand/AppDelegate.swift @@ -0,0 +1,40 @@ +// +// AppDelegate.swift +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} + diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/Contents.json b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..4590729 --- /dev/null +++ b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "cmd20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "cmd40-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "cmd29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "cmd58.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "cmd40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "cmd80.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "cmd76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "cmd152.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "cmd167.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "cmd1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd1024.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd1024.png new file mode 100644 index 0000000..1b94956 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd1024.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd152.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd152.png new file mode 100644 index 0000000..e191ab0 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd152.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd167.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd167.png new file mode 100644 index 0000000..82d08f8 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd167.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd20.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd20.png new file mode 100644 index 0000000..81d0307 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd20.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd29.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd29.png new file mode 100644 index 0000000..bf52f66 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd29.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40-1.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40-1.png new file mode 100644 index 0000000..b24189c Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40-1.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40.png new file mode 100644 index 0000000..b24189c Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd40.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd58.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd58.png new file mode 100644 index 0000000..5ecbf1d Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd58.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd76.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd76.png new file mode 100644 index 0000000..1cc5239 Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd76.png differ diff --git a/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd80.png b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd80.png new file mode 100644 index 0000000..df540ac Binary files /dev/null and b/KeyCommand/KeyCommand/Assets.xcassets/AppIcon.appiconset/cmd80.png differ diff --git a/KeyCommand/KeyCommand/Base.lproj/LaunchScreen.storyboard b/KeyCommand/KeyCommand/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..48cf7b7 --- /dev/null +++ b/KeyCommand/KeyCommand/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeyCommand/KeyCommand/Base.lproj/Localizable.strings b/KeyCommand/KeyCommand/Base.lproj/Localizable.strings new file mode 100644 index 0000000..05a6c0a --- /dev/null +++ b/KeyCommand/KeyCommand/Base.lproj/Localizable.strings @@ -0,0 +1,43 @@ +// +// Localizable.strings +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +"LowPriority" = "Low priority"; +"MediumPriority" = "Medium priority"; +"HighPriority" = "High priority"; + +"CloseWindow" = "Close window"; + +"none" = "None"; +"low" = "Low"; +"medium" = "Medium"; +"high" = "High"; diff --git a/KeyCommand/KeyCommand/Base.lproj/Main.storyboard b/KeyCommand/KeyCommand/Base.lproj/Main.storyboard new file mode 100644 index 0000000..8d88e33 --- /dev/null +++ b/KeyCommand/KeyCommand/Base.lproj/Main.storyboard @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeyCommand/KeyCommand/DetailViewController.swift b/KeyCommand/KeyCommand/DetailViewController.swift new file mode 100644 index 0000000..1caece9 --- /dev/null +++ b/KeyCommand/KeyCommand/DetailViewController.swift @@ -0,0 +1,69 @@ +// +// DetailViewController.swift +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class DetailViewController: UIViewController { + var priority = UYLPriority.none { + didSet { + configureView() + } + } + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(input: UIKeyCommand.inputEscape, + modifierFlags: [], + action: #selector(DetailViewController.dismissAction), + discoverabilityTitle: NSLocalizedString("CloseWindow", comment: "Close window")) + ] + } + + override var canBecomeFirstResponder: Bool { + return true + } + + @IBAction func dismissAction() { + dismiss(animated: true, completion: nil) + } + + override func viewDidLoad() { + super.viewDidLoad() + configureView() + } + + private func configureView() { + title = priority.label() + view.backgroundColor = priority.color() + } +} diff --git a/KeyCommand/KeyCommand/Info.plist b/KeyCommand/KeyCommand/Info.plist new file mode 100644 index 0000000..5e08258 --- /dev/null +++ b/KeyCommand/KeyCommand/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/KeyCommand/KeyCommand/OptionViewController.swift b/KeyCommand/KeyCommand/OptionViewController.swift new file mode 100644 index 0000000..6e2df84 --- /dev/null +++ b/KeyCommand/KeyCommand/OptionViewController.swift @@ -0,0 +1,123 @@ +// +// OptionViewController.swift +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class OptionViewController: UIViewController { + private enum InputKey: String { + case low = "1" + case medium = "2" + case high = "3" + } + + // Override keyCommands and return the three + // key commands for this view controller. + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(input: InputKey.low.rawValue, + modifierFlags: .command, + action: #selector(OptionViewController.performCommand(sender:)), + discoverabilityTitle: NSLocalizedString("LowPriority", comment: "Low priority")), + + UIKeyCommand(input: InputKey.medium.rawValue, + modifierFlags: .command, + action: #selector(OptionViewController.performCommand(sender:)), + discoverabilityTitle: NSLocalizedString("MediumPriority", comment: "Medium priority")), + + UIKeyCommand(input: InputKey.high.rawValue, + modifierFlags: .command, + action: #selector(OptionViewController.performCommand(sender:)), + discoverabilityTitle: NSLocalizedString("HighPriority", comment: "High priority")) + ] + } + + @objc func performCommand(sender: UIKeyCommand) { + guard let key = InputKey(rawValue: sender.input!) else { + return + } + switch key { + case .low: performSegue(withIdentifier: .low, sender: self) + case .medium: performSegue(withIdentifier: .medium, sender: self) + case .high: performSegue(withIdentifier: .high, sender: self) + } + } + + // You can also add key commands without overriding the + // keyCommands property. For example you could call the + // following function from viewDidLoad: + +// private func setupCommands() { +// let lowCommand = UIKeyCommand(input: InputKey.low.rawValue, +// modifierFlags: .command, +// action: #selector(OptionViewController.performCommand(sender:)), +// discoverabilityTitle: NSLocalizedString("LowPriority", comment: "Low priority")) +// addKeyCommand(lowCommand) +// +// let mediumCommand = UIKeyCommand(input: InputKey.medium.rawValue, +// modifierFlags: .command, +// action: #selector(OptionViewController.performCommand(sender:)), +// discoverabilityTitle: NSLocalizedString("MediumPriority", comment: "Medium priority")) +// addKeyCommand(mediumCommand) +// +// let highCommand = UIKeyCommand(input: InputKey.high.rawValue, +// modifierFlags: .command, +// action: #selector(OptionViewController.performCommand(sender:)), +// discoverabilityTitle: NSLocalizedString("HighPriority", comment: "High priority")) +// addKeyCommand(highCommand) +// } +} + +extension OptionViewController: SegueHandlerType { + enum SegueIdentifier: String { + case low + case medium + case high + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + guard let navController = segue.destination as? UINavigationController, + let viewController = navController.topViewController as? DetailViewController else { + fatalError("Expected embedded DetailViewController") + } + + switch segueIdentifierForSegue(segue: segue) { + case .low: + viewController.priority = .low + case .medium: + viewController.priority = .medium + case .high: + viewController.priority = .high + } + } +} diff --git a/KeyCommand/KeyCommand/SegueHandlerType.swift b/KeyCommand/KeyCommand/SegueHandlerType.swift new file mode 100644 index 0000000..26f1f97 --- /dev/null +++ b/KeyCommand/KeyCommand/SegueHandlerType.swift @@ -0,0 +1,51 @@ +// +// SegueHandlerType.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +protocol SegueHandlerType { + associatedtype SegueIdentifier: RawRepresentable +} + +extension SegueHandlerType where Self: UIViewController, SegueIdentifier.RawValue == String { + func performSegue(withIdentifier segueIdentifier: SegueIdentifier, sender: AnyObject?) { + performSegue(withIdentifier: segueIdentifier.rawValue, sender: sender) + } + + func segueIdentifierForSegue(segue: UIStoryboardSegue) -> SegueIdentifier { + guard let identifier = segue.identifier, + let segueIdentifier = SegueIdentifier(rawValue: identifier) else { + fatalError("Unknown Segue Identifier \(segue.identifier ?? "Missing")") + } + return segueIdentifier + } +} diff --git a/KeyCommand/KeyCommand/UYLPriority.swift b/KeyCommand/KeyCommand/UYLPriority.swift new file mode 100644 index 0000000..67e2eae --- /dev/null +++ b/KeyCommand/KeyCommand/UYLPriority.swift @@ -0,0 +1,54 @@ +// +// UYLOption.swift +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +enum UYLPriority: String { + case none + case low + case medium + case high + + func label() -> String { + return NSLocalizedString(self.rawValue, comment: "Priority") + } + + func color() -> UIColor { + switch self { + case .none: return .white + case .low: return .green + case .medium: return .yellow + case .high: return .red + } + } +} diff --git a/KeyCommand/KeyCommandObjC/AppDelegate.h b/KeyCommand/KeyCommandObjC/AppDelegate.h new file mode 100644 index 0000000..99bf474 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/AppDelegate.h @@ -0,0 +1,43 @@ +// +// AppDelegate.h +// KeyCommandObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/KeyCommand/KeyCommandObjC/AppDelegate.m b/KeyCommand/KeyCommandObjC/AppDelegate.m new file mode 100644 index 0000000..b329e8f --- /dev/null +++ b/KeyCommand/KeyCommandObjC/AppDelegate.m @@ -0,0 +1,37 @@ +// +// AppDelegate.m +// KeyCommandObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/KeyCommand/KeyCommandObjC/Base.lproj/Main.storyboard b/KeyCommand/KeyCommandObjC/Base.lproj/Main.storyboard new file mode 100644 index 0000000..8fecc05 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/Base.lproj/Main.storyboard @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeyCommand/KeyCommandObjC/DetailViewController.h b/KeyCommand/KeyCommandObjC/DetailViewController.h new file mode 100644 index 0000000..b1c85da --- /dev/null +++ b/KeyCommand/KeyCommandObjC/DetailViewController.h @@ -0,0 +1,40 @@ +// +// DetailViewController.h +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "UYLPriority.h" + +@interface DetailViewController : UIViewController +@property (nonatomic,assign) UYLPriorityLevel priority; +@end diff --git a/KeyCommand/KeyCommandObjC/DetailViewController.m b/KeyCommand/KeyCommandObjC/DetailViewController.m new file mode 100644 index 0000000..e8bee98 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/DetailViewController.m @@ -0,0 +1,71 @@ +// +// DetailViewController.m +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "DetailViewController.h" +#import "UYLPriority.h" + +@implementation DetailViewController + +- (NSArray *)keyCommands { + return @[ + [UIKeyCommand keyCommandWithInput:UIKeyInputEscape + modifierFlags:0 + action:@selector(dismissAction) + discoverabilityTitle:NSLocalizedString(@"CloseWindow", @"Close window")] + ]; +} + +- (BOOL)canBecomeFirstResponder { + return YES; +} + +- (void)setPriority:(UYLPriorityLevel)priority { + _priority = priority; + [self configureView]; +} + +- (IBAction)dismissAction { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [self configureView]; +} + +- (void)configureView { + self.title = [UYLPriority labelForPriorityLevel:self.priority]; + self.view.backgroundColor = [UYLPriority colorForPriorityLevel:self.priority]; +} + +@end diff --git a/KeyCommand/KeyCommandObjC/Info.plist b/KeyCommand/KeyCommandObjC/Info.plist new file mode 100644 index 0000000..cf92535 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.1 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/KeyCommand/KeyCommandObjC/OptionViewController.h b/KeyCommand/KeyCommandObjC/OptionViewController.h new file mode 100644 index 0000000..525c775 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/OptionViewController.h @@ -0,0 +1,39 @@ +// +// OptionViewController.h +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface OptionViewController : UIViewController + +@end diff --git a/KeyCommand/KeyCommandObjC/OptionViewController.m b/KeyCommand/KeyCommandObjC/OptionViewController.m new file mode 100644 index 0000000..24857e5 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/OptionViewController.m @@ -0,0 +1,109 @@ +// +// OptionViewController.m +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "OptionViewController.h" +#import "DetailViewController.h" +#import "UYLPriority.h" + +@implementation OptionViewController + +// Override keyCommands and return the three +// key commands for this view controller. + +static NSString *inputKeyLow = @"1"; +static NSString *inputKeyMedium = @"2"; +static NSString *inputKeyHigh = @"3"; + +- (NSArray *)keyCommands { + return @[ + [UIKeyCommand keyCommandWithInput:inputKeyLow + modifierFlags:UIKeyModifierCommand + action:@selector(performCommand:) + discoverabilityTitle:NSLocalizedString(@"LowPriority", @"Low priority")], + [UIKeyCommand keyCommandWithInput:inputKeyMedium + modifierFlags:UIKeyModifierCommand + action:@selector(performCommand:) + discoverabilityTitle:NSLocalizedString(@"MediumPriority", @"Medium priority")], + [UIKeyCommand keyCommandWithInput:inputKeyHigh + modifierFlags:UIKeyModifierCommand + action:@selector(performCommand:) + discoverabilityTitle:NSLocalizedString(@"HighPriority", @"High priority")] + ]; +} + +- (void)performCommand:(UIKeyCommand *)sender { + NSString *key = sender.input; + if ([key isEqualToString:inputKeyLow]) { + [self performSegueWithIdentifier:UYLPriorityIdentifierLow sender:self]; + } else if ([key isEqualToString:inputKeyMedium]) { + [self performSegueWithIdentifier:UYLPriorityIdentifierMedium sender:self]; + } else if ([key isEqualToString:inputKeyHigh]) { + [self performSegueWithIdentifier:UYLPriorityIdentifierHigh sender:self]; + } +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + + if ([segue.destinationViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *navController = segue.destinationViewController; + + if ([navController.topViewController isKindOfClass:[DetailViewController class]]) { + DetailViewController *viewController = (DetailViewController *)navController.topViewController; + viewController.priority = [UYLPriority priorityLevelForIdentifier:segue.identifier]; + } + } +} + +// You can also add key commands without overriding the +// keyCommands property. For example you could call the +// following function from viewDidLoad: + +//- (void)setupCommands { +// UIKeyCommand *lowCommand = [UIKeyCommand keyCommandWithInput:inputKeyLow +// modifierFlags:UIKeyModifierCommand +// action:@selector(performCommand:) +// discoverabilityTitle:NSLocalizedString(@"LowPriority", @"Low priority")]; +// [self addKeyCommand:lowCommand]; +// +// UIKeyCommand *mediumCommand = [UIKeyCommand keyCommandWithInput:inputKeyMedium +// modifierFlags:UIKeyModifierCommand +// action:@selector(performCommand:) discoverabilityTitle:NSLocalizedString(@"MediumPriority", @"Medium priority")]; +// [self addKeyCommand:mediumCommand]; +// +// UIKeyCommand *highCommand = [UIKeyCommand keyCommandWithInput:inputKeyHigh +// modifierFlags:UIKeyModifierCommand +// action:@selector(performCommand:) discoverabilityTitle:NSLocalizedString(@"HighPriority", @"High priority")]; +// [self addKeyCommand:highCommand]; +//} + +@end diff --git a/KeyCommand/KeyCommandObjC/UYLPriority.h b/KeyCommand/KeyCommandObjC/UYLPriority.h new file mode 100644 index 0000000..2c568d8 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/UYLPriority.h @@ -0,0 +1,55 @@ +// +// UYLPriority.h +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +typedef NS_ENUM(NSInteger, UYLPriorityLevel) { + UYLPriorityNone, + UYLPriorityLow, + UYLPriorityMedium, + UYLPriorityHigh +}; + +@interface UYLPriority : NSObject + +extern NSString *UYLPriorityIdentifierNone; +extern NSString *UYLPriorityIdentifierLow; +extern NSString *UYLPriorityIdentifierMedium; +extern NSString *UYLPriorityIdentifierHigh; + ++ (NSString *)labelForPriorityLevel:(UYLPriorityLevel)level; ++ (UYLPriorityLevel)priorityLevelForIdentifier:(NSString *)identifier; ++ (UIColor *)colorForPriorityLevel:(UYLPriorityLevel)level; + +@end diff --git a/KeyCommand/KeyCommandObjC/UYLPriority.m b/KeyCommand/KeyCommandObjC/UYLPriority.m new file mode 100644 index 0000000..fd94ba3 --- /dev/null +++ b/KeyCommand/KeyCommandObjC/UYLPriority.m @@ -0,0 +1,80 @@ +// +// UYLPriority.m +// KeyCommand +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "UYLPriority.h" + +@implementation UYLPriority + +NSString *UYLPriorityIdentifierNone = @"none"; +NSString *UYLPriorityIdentifierLow = @"low"; +NSString *UYLPriorityIdentifierMedium = @"medium"; +NSString *UYLPriorityIdentifierHigh = @"high"; + ++ (NSString *)labelForPriorityLevel:(UYLPriorityLevel)level { + + switch (level) { + case UYLPriorityNone: + return NSLocalizedString(UYLPriorityIdentifierNone, @"No Priority"); + case UYLPriorityLow: + return NSLocalizedString(UYLPriorityIdentifierLow, @"Low Priority"); + case UYLPriorityMedium: + return NSLocalizedString(UYLPriorityIdentifierMedium, @"Medium Priority"); + case UYLPriorityHigh: + return NSLocalizedString(UYLPriorityIdentifierHigh, @"High Priority"); + } +} + ++ (UYLPriorityLevel)priorityLevelForIdentifier:(NSString *)identifier { + if ([identifier isEqualToString:UYLPriorityIdentifierLow]) { + return UYLPriorityLow; + } + if ([identifier isEqualToString:UYLPriorityIdentifierMedium]) { + return UYLPriorityMedium; + } + if ([identifier isEqualToString:UYLPriorityIdentifierHigh]) { + return UYLPriorityHigh; + } + return UYLPriorityNone; +} + ++ (UIColor *)colorForPriorityLevel:(UYLPriorityLevel)level { + + switch (level) { + case UYLPriorityNone: return UIColor.whiteColor; + case UYLPriorityLow: return UIColor.greenColor; + case UYLPriorityMedium: return UIColor.yellowColor; + case UYLPriorityHigh: return UIColor.redColor; + } +} + +@end diff --git a/KeyCommand/KeyCommandObjC/main.m b/KeyCommand/KeyCommandObjC/main.m new file mode 100644 index 0000000..b91692d --- /dev/null +++ b/KeyCommand/KeyCommandObjC/main.m @@ -0,0 +1,41 @@ +// +// main.m +// KeyCommandObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/KeyCommand/README.md b/KeyCommand/README.md new file mode 100644 index 0000000..fea205c --- /dev/null +++ b/KeyCommand/README.md @@ -0,0 +1,16 @@ +### Adding Hardware Keyboard Shortcuts + +An example showing how to add hardware keyboard shortcuts to an +App by overriding the `keyCommands` property of a view controller. + +This Xcode project contains both Swift and Objective-C targets. + +See the following blog post for further details: + ++ [Adding Hardware Keyboard Support](https://useyourloaf.com/blog/adding-hardware-keyboard-shortcuts/) + +#### Version History + ++ Version 1.2 01 Jan 2020 Updated for Xcode 11 ++ Version 1.1 26 Oct 2017 Updated for Xcode 9 and Swift 4 ++ Version 1.0 12 Nov 2016 Initial Version diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f512a3f --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2013, Keith Harrison +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of Keith Harrison nor the names of contributors + may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + \ No newline at end of file diff --git a/Margins/Margins.playground/Contents.swift b/Margins/Margins.playground/Contents.swift new file mode 100644 index 0000000..330e633 --- /dev/null +++ b/Margins/Margins.playground/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport + +let viewController = MarginViewController() +viewController.view.backgroundColor = .white +viewController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 640) +PlaygroundPage.current.liveView = viewController.view + +viewController.redView.preservesSuperviewLayoutMargins = true + +viewController.stackView.preservesSuperviewLayoutMargins = true +viewController.stackView.isLayoutMarginsRelativeArrangement = true + +viewController.stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) diff --git a/Margins/Margins.playground/Sources/MarginViewController.swift b/Margins/Margins.playground/Sources/MarginViewController.swift new file mode 100644 index 0000000..892fbba --- /dev/null +++ b/Margins/Margins.playground/Sources/MarginViewController.swift @@ -0,0 +1,95 @@ +// +// MarginViewController.swift +// Margins +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +public class MarginViewController: UIViewController { + + override public func viewDidLoad() { + super.viewDidLoad() + setupViews() + } + + public lazy var redView: UIView = { + return self.simpleView(color: .red) + }() + + public lazy var stackView: UIStackView = { + return UIStackView() + }() + + private func setupViews() { + view.addSubview(redView) + NSLayoutConstraint.activate([ + redView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + redView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + redView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) + + let yellowView = simpleView(color: .yellow) + redView.addSubview(yellowView) + let redMargins = redView.layoutMarginsGuide + NSLayoutConstraint.activate([ + yellowView.leadingAnchor.constraint(equalTo: redMargins.leadingAnchor), + yellowView.trailingAnchor.constraint(equalTo: redMargins.trailingAnchor), + yellowView.topAnchor.constraint(equalTo: redMargins.topAnchor), + yellowView.bottomAnchor.constraint(equalTo: redMargins.bottomAnchor) + ]) + + let blueView = simpleView(color: .blue) + stackView.addArrangedSubview(blueView) + let greenView = simpleView(color: .green) + stackView.addArrangedSubview(greenView) + stackView.spacing = 8.0 + stackView.distribution = .fillEqually + stackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(stackView) + + NSLayoutConstraint.activate([ + stackView.topAnchor.constraint(equalTo: redView.bottomAnchor), + stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + + stackView.heightAnchor.constraint(equalTo: redView.heightAnchor) + ]) + } + + private func simpleView(color: UIColor) -> UIView { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = color + return view + } +} + diff --git a/Margins/Margins.playground/contents.xcplayground b/Margins/Margins.playground/contents.xcplayground new file mode 100644 index 0000000..5da2641 --- /dev/null +++ b/Margins/Margins.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Margins/Margins.playground/timeline.xctimeline b/Margins/Margins.playground/timeline.xctimeline new file mode 100644 index 0000000..bf468af --- /dev/null +++ b/Margins/Margins.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/Margins/Margins.xcodeproj/project.pbxproj b/Margins/Margins.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d330e67 --- /dev/null +++ b/Margins/Margins.xcodeproj/project.pbxproj @@ -0,0 +1,328 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53E307761EB33A650055FFCB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E307751EB33A650055FFCB /* AppDelegate.swift */; }; + 53E3077B1EB33A650055FFCB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53E307791EB33A650055FFCB /* Main.storyboard */; }; + 53E3077D1EB33A650055FFCB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53E3077C1EB33A650055FFCB /* Assets.xcassets */; }; + 53E307801EB33A650055FFCB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53E3077E1EB33A650055FFCB /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53E307721EB33A650055FFCB /* Margins.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Margins.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53E307751EB33A650055FFCB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53E3077A1EB33A650055FFCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53E3077C1EB33A650055FFCB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53E3077F1EB33A650055FFCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53E307811EB33A650055FFCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53FE21E91EB7487400DAC6C2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53E3076F1EB33A650055FFCB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53E307691EB33A650055FFCB = { + isa = PBXGroup; + children = ( + 53FE21E91EB7487400DAC6C2 /* README.md */, + 53E307741EB33A650055FFCB /* Margins */, + 53E307731EB33A650055FFCB /* Products */, + ); + sourceTree = ""; + }; + 53E307731EB33A650055FFCB /* Products */ = { + isa = PBXGroup; + children = ( + 53E307721EB33A650055FFCB /* Margins.app */, + ); + name = Products; + sourceTree = ""; + }; + 53E307741EB33A650055FFCB /* Margins */ = { + isa = PBXGroup; + children = ( + 53E307751EB33A650055FFCB /* AppDelegate.swift */, + 53E307791EB33A650055FFCB /* Main.storyboard */, + 53E3077C1EB33A650055FFCB /* Assets.xcassets */, + 53E3077E1EB33A650055FFCB /* LaunchScreen.storyboard */, + 53E307811EB33A650055FFCB /* Info.plist */, + ); + path = Margins; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53E307711EB33A650055FFCB /* Margins */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53E307841EB33A650055FFCB /* Build configuration list for PBXNativeTarget "Margins" */; + buildPhases = ( + 53E3076E1EB33A650055FFCB /* Sources */, + 53E3076F1EB33A650055FFCB /* Frameworks */, + 53E307701EB33A650055FFCB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Margins; + productName = Margins; + productReference = 53E307721EB33A650055FFCB /* Margins.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53E3076A1EB33A650055FFCB /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 1030; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53E307711EB33A650055FFCB = { + CreatedOnToolsVersion = 8.3.2; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53E3076D1EB33A650055FFCB /* Build configuration list for PBXProject "Margins" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53E307691EB33A650055FFCB; + productRefGroup = 53E307731EB33A650055FFCB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53E307711EB33A650055FFCB /* Margins */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53E307701EB33A650055FFCB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E307801EB33A650055FFCB /* LaunchScreen.storyboard in Resources */, + 53E3077D1EB33A650055FFCB /* Assets.xcassets in Resources */, + 53E3077B1EB33A650055FFCB /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53E3076E1EB33A650055FFCB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E307761EB33A650055FFCB /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53E307791EB33A650055FFCB /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53E3077A1EB33A650055FFCB /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53E3077E1EB33A650055FFCB /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53E3077F1EB33A650055FFCB /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53E307821EB33A650055FFCB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53E307831EB33A650055FFCB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53E307851EB33A650055FFCB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Margins/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Margins; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53E307861EB33A650055FFCB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Margins/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Margins; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53E3076D1EB33A650055FFCB /* Build configuration list for PBXProject "Margins" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53E307821EB33A650055FFCB /* Debug */, + 53E307831EB33A650055FFCB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53E307841EB33A650055FFCB /* Build configuration list for PBXNativeTarget "Margins" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53E307851EB33A650055FFCB /* Debug */, + 53E307861EB33A650055FFCB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53E3076A1EB33A650055FFCB /* Project object */; +} diff --git a/Margins/Margins.xcworkspace/contents.xcworkspacedata b/Margins/Margins.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b988434 --- /dev/null +++ b/Margins/Margins.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Margins/Margins.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Margins/Margins.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Margins/Margins.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Margins/Margins/AppDelegate.swift b/Margins/Margins/AppDelegate.swift new file mode 100644 index 0000000..de79b3d --- /dev/null +++ b/Margins/Margins/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// Margins +// +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/Margins/Margins/Assets.xcassets/AppIcon.appiconset/Contents.json b/Margins/Margins/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/Margins/Margins/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Margins/Margins/Base.lproj/LaunchScreen.storyboard b/Margins/Margins/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Margins/Margins/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Margins/Margins/Base.lproj/Main.storyboard b/Margins/Margins/Base.lproj/Main.storyboard new file mode 100644 index 0000000..17351d7 --- /dev/null +++ b/Margins/Margins/Base.lproj/Main.storyboard @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Margins/Margins/Info.plist b/Margins/Margins/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Margins/Margins/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Margins/README.md b/Margins/README.md new file mode 100644 index 0000000..74ee017 --- /dev/null +++ b/Margins/README.md @@ -0,0 +1,7 @@ +### Preserving Superview Margins + +Example of how to use `preservesSuperviewLayoutMargins`. + +See the following blog post: + ++ [Preserves Superview Layout Margins](https://useyourloaf.com/blog/preserves-superview-layout-margins/) \ No newline at end of file diff --git a/MasterSlide/MasterSlide/MainWindow.xib b/MasterSlide/MasterSlide/MainWindow.xib deleted file mode 100644 index de12c87..0000000 --- a/MasterSlide/MasterSlide/MainWindow.xib +++ /dev/null @@ -1,337 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBProxyObject - IBUINavigationController - IBUIViewController - IBUICustomObject - IBUISplitViewController - IBUIWindow - IBUITableViewController - IBUINavigationItem - IBUINavigationBar - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - IBIPadFramework - - - - 1316 - - {768, 1024} - - - - - 1 - MSAxIDEAA - - NO - NO - - 2 - - IBIPadFramework - YES - - - - - 2 - - - 3 - 3 - - IBIPadFramework - YES - - - - 2 - - - 1 - 1 - - IBIPadFramework - NO - - - 256 - {0, 0} - _NS:839 - YES - YES - IBIPadFramework - - - - Master - - Master - IBIPadFramework - - - UYLMasterViewController - - 2 - - - 1 - 1 - - IBIPadFramework - NO - NO - - - - - Detail - - - UYLDetailViewController - - 1 - 1 - - IBIPadFramework - NO - - - - - - - - delegate - - - - 5 - - - - window - - - - 14 - - - - splitViewController - - - - 13 - - - - detailViewController - - - - 35 - - - - - - 0 - - - - - - 2 - - - - - -1 - - - File's Owner - - - 4 - - - App Delegate - - - -2 - - - - - 6 - - - - - - - - - 15 - - - - - - 8 - - - - - - - - - 10 - - - - - - - - 11 - - - - - 9 - - - - - - - UIApplication - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UYLMasterViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UYLDetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UYLAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 35 - - - - - UYLAppDelegate - UIResponder - - UISplitViewController - UIWindow - - - - splitViewController - UISplitViewController - - - window - UIWindow - - - - IBProjectSource - ./Classes/UYLAppDelegate.h - - - - UYLDetailViewController - UIViewController - - detailDescriptionLabel - UILabel - - - detailDescriptionLabel - - detailDescriptionLabel - UILabel - - - - IBProjectSource - ./Classes/UYLDetailViewController.h - - - - UYLMasterViewController - UITableViewController - - detailViewController - UYLDetailViewController - - - detailViewController - - detailViewController - UYLDetailViewController - - - - IBProjectSource - ./Classes/UYLMasterViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 933 - - diff --git a/MasterSlide/MasterSlide/en.lproj/UYLDetailViewController.xib b/MasterSlide/MasterSlide/en.lproj/UYLDetailViewController.xib deleted file mode 100644 index 0e8a58b..0000000 --- a/MasterSlide/MasterSlide/en.lproj/UYLDetailViewController.xib +++ /dev/null @@ -1,410 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBUISwipeGestureRecognizer - IBUITapGestureRecognizer - IBUIToolbar - IBUIView - IBUILabel - IBProxyObject - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - - - - 290 - {768, 44} - - - - _NS:372 - NO - NO - IBIPadFramework - - - - - 292 - {{363, 11}, {42, 21}} - - - - _NS:345 - NO - YES - 7 - NO - IBIPadFramework - Detail - - 1 - MCAwIDAAA - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 274 - - - - 298 - {{20, 470}, {728, 21}} - - - - - 3 - MQA - - YES - - NO - IBIPadFramework - Select an item - - - 1 - 10 - 1 - - 1 - 4 - - - Helvetica - 14 - 16 - - - - {{0, 44}, {768, 960}} - - - _NS:212 - - 3 - MQA - - 2 - - - - IBIPadFramework - - - {{0, 20}, {768, 1004}} - - - - - YES - - - 2 - - - IBUISplitViewDetailSimulatedSizeMetrics - - YES - - - - - - {768, 1024} - {703, 768} - - - IBIPadFramework - Detail - IBUISplitViewController - - IBUISplitViewControllerContentSizeLocation - IBUISplitViewControllerContentSizeLocationDetail - - - IBIPadFramework - - - - 2 - - - - - - - - view - - - - 12 - - - - toolbar - - - - 72 - - - - detailTitle - - - - 74 - - - - detailDescriptionLabel - - - - 66 - - - - handleTap: - - - - 97 - - - - handleSwipeRight: - - - - 98 - - - - handleSwipeLeft: - - - - 102 - - - - gestureRecognizers - - - NSArray - YES - - 111 - - - - gestureRecognizers - - - NSArray - YES - - 112 - - - - gestureRecognizers - - - NSArray - YES - - 113 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 8 - - - - - - - - - - 67 - - - - - - 73 - - - - - 110 - - - - - - - - 45 - - - - - 79 - - - - - 81 - - - - - 75 - - - - - - - UYLDetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 113 - - - - - UYLDetailViewController - UIViewController - - UISwipeGestureRecognizer - UISwipeGestureRecognizer - UITapGestureRecognizer - - - - handleSwipeLeft: - UISwipeGestureRecognizer - - - handleSwipeRight: - UISwipeGestureRecognizer - - - handleTap: - UITapGestureRecognizer - - - - UILabel - UILabel - UIToolbar - - - - detailDescriptionLabel - UILabel - - - detailTitle - UILabel - - - toolbar - UIToolbar - - - - IBProjectSource - ./Classes/UYLDetailViewController.h - - - - - 0 - IBIPadFramework - YES - 3 - 933 - - diff --git a/MasterSlide/MasterSlide/en.lproj/UYLMasterViewController.xib b/MasterSlide/MasterSlide/en.lproj/UYLMasterViewController.xib deleted file mode 100644 index aac88df..0000000 --- a/MasterSlide/MasterSlide/en.lproj/UYLMasterViewController.xib +++ /dev/null @@ -1,140 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - {320, 852} - - - - _NS:408 - - 3 - MQA - - YES - IBIPadFramework - YES - 1 - 0 - YES - 44 - 22 - 22 - - - - - - - view - - - - 11 - - - - delegate - - - - 10 - - - - dataSource - - - - 9 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 7 - - - - - - - UYLMasterViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 11 - - - - - UYLMasterViewController - UIViewController - - IBProjectSource - ./Classes/UYLMasterViewController.h - - - - - 0 - IBIPadFramework - YES - 3 - 933 - - diff --git a/Motion/Motion.xcodeproj/project.pbxproj b/Motion/Motion.xcodeproj/project.pbxproj new file mode 100644 index 0000000..928742d --- /dev/null +++ b/Motion/Motion.xcodeproj/project.pbxproj @@ -0,0 +1,355 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 530D9CF223C928930087DFA0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 530D9CF123C928930087DFA0 /* LaunchScreen.storyboard */; }; + 5365E38B1875D15500466DA8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5365E38A1875D15500466DA8 /* Foundation.framework */; }; + 5365E38D1875D15500466DA8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5365E38C1875D15500466DA8 /* CoreGraphics.framework */; }; + 5365E38F1875D15500466DA8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5365E38E1875D15500466DA8 /* UIKit.framework */; }; + 5365E3951875D15500466DA8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5365E3931875D15500466DA8 /* InfoPlist.strings */; }; + 5365E3971875D15500466DA8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5365E3961875D15500466DA8 /* main.m */; }; + 5365E39B1875D15500466DA8 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5365E39A1875D15500466DA8 /* UYLAppDelegate.m */; }; + 5365E39E1875D15500466DA8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5365E39C1875D15500466DA8 /* Main.storyboard */; }; + 5365E3A11875D15500466DA8 /* UYLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5365E3A01875D15500466DA8 /* UYLViewController.m */; }; + 5365E3A31875D15500466DA8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5365E3A21875D15500466DA8 /* Images.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 530D9CF123C928930087DFA0 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5365E3871875D15500466DA8 /* Motion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Motion.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5365E38A1875D15500466DA8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5365E38C1875D15500466DA8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5365E38E1875D15500466DA8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5365E3921875D15500466DA8 /* Motion-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Motion-Info.plist"; sourceTree = ""; }; + 5365E3941875D15500466DA8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5365E3961875D15500466DA8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5365E3991875D15500466DA8 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 5365E39A1875D15500466DA8 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 5365E39D1875D15500466DA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5365E39F1875D15500466DA8 /* UYLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; + 5365E3A01875D15500466DA8 /* UYLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; + 5365E3A21875D15500466DA8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5365E3A91875D15500466DA8 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 538A825E18775F0E0097C908 /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5365E3841875D15500466DA8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5365E38D1875D15500466DA8 /* CoreGraphics.framework in Frameworks */, + 5365E38F1875D15500466DA8 /* UIKit.framework in Frameworks */, + 5365E38B1875D15500466DA8 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5365E37E1875D15500466DA8 = { + isa = PBXGroup; + children = ( + 538A825E18775F0E0097C908 /* README */, + 5365E3901875D15500466DA8 /* Motion */, + 5365E3891875D15500466DA8 /* Frameworks */, + 5365E3881875D15500466DA8 /* Products */, + ); + sourceTree = ""; + }; + 5365E3881875D15500466DA8 /* Products */ = { + isa = PBXGroup; + children = ( + 5365E3871875D15500466DA8 /* Motion.app */, + ); + name = Products; + sourceTree = ""; + }; + 5365E3891875D15500466DA8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5365E38A1875D15500466DA8 /* Foundation.framework */, + 5365E38C1875D15500466DA8 /* CoreGraphics.framework */, + 5365E38E1875D15500466DA8 /* UIKit.framework */, + 5365E3A91875D15500466DA8 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5365E3901875D15500466DA8 /* Motion */ = { + isa = PBXGroup; + children = ( + 5365E3991875D15500466DA8 /* UYLAppDelegate.h */, + 5365E39A1875D15500466DA8 /* UYLAppDelegate.m */, + 5365E39C1875D15500466DA8 /* Main.storyboard */, + 530D9CF123C928930087DFA0 /* LaunchScreen.storyboard */, + 5365E39F1875D15500466DA8 /* UYLViewController.h */, + 5365E3A01875D15500466DA8 /* UYLViewController.m */, + 5365E3A21875D15500466DA8 /* Images.xcassets */, + 5365E3911875D15500466DA8 /* Supporting Files */, + ); + path = Motion; + sourceTree = ""; + }; + 5365E3911875D15500466DA8 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5365E3921875D15500466DA8 /* Motion-Info.plist */, + 5365E3931875D15500466DA8 /* InfoPlist.strings */, + 5365E3961875D15500466DA8 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5365E3861875D15500466DA8 /* Motion */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5365E3B91875D15500466DA8 /* Build configuration list for PBXNativeTarget "Motion" */; + buildPhases = ( + 5365E3831875D15500466DA8 /* Sources */, + 5365E3841875D15500466DA8 /* Frameworks */, + 5365E3851875D15500466DA8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Motion; + productName = Motion; + productReference = 5365E3871875D15500466DA8 /* Motion.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5365E37F1875D15500466DA8 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 5365E3821875D15500466DA8 /* Build configuration list for PBXProject "Motion" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5365E37E1875D15500466DA8; + productRefGroup = 5365E3881875D15500466DA8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5365E3861875D15500466DA8 /* Motion */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5365E3851875D15500466DA8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5365E3A31875D15500466DA8 /* Images.xcassets in Resources */, + 530D9CF223C928930087DFA0 /* LaunchScreen.storyboard in Resources */, + 5365E3951875D15500466DA8 /* InfoPlist.strings in Resources */, + 5365E39E1875D15500466DA8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5365E3831875D15500466DA8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5365E3971875D15500466DA8 /* main.m in Sources */, + 5365E39B1875D15500466DA8 /* UYLAppDelegate.m in Sources */, + 5365E3A11875D15500466DA8 /* UYLViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5365E3931875D15500466DA8 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5365E3941875D15500466DA8 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5365E39C1875D15500466DA8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5365E39D1875D15500466DA8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5365E3B71875D15500466DA8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5365E3B81875D15500466DA8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5365E3BA1875D15500466DA8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "Motion/Motion-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5365E3BB1875D15500466DA8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "Motion/Motion-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5365E3821875D15500466DA8 /* Build configuration list for PBXProject "Motion" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5365E3B71875D15500466DA8 /* Debug */, + 5365E3B81875D15500466DA8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5365E3B91875D15500466DA8 /* Build configuration list for PBXNativeTarget "Motion" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5365E3BA1875D15500466DA8 /* Debug */, + 5365E3BB1875D15500466DA8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5365E37F1875D15500466DA8 /* Project object */; +} diff --git a/Motion/Motion/Base.lproj/Main.storyboard b/Motion/Motion/Base.lproj/Main.storyboard new file mode 100644 index 0000000..60e9d60 --- /dev/null +++ b/Motion/Motion/Base.lproj/Main.storyboard @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Motion/Motion/Images.xcassets/AppIcon.appiconset/Contents.json b/Motion/Motion/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..19882d5 --- /dev/null +++ b/Motion/Motion/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Motion/Motion/Images.xcassets/Contents.json b/Motion/Motion/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Motion/Motion/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Motion/Motion/Images.xcassets/grid.imageset/Contents.json b/Motion/Motion/Images.xcassets/grid.imageset/Contents.json new file mode 100644 index 0000000..72e7291 --- /dev/null +++ b/Motion/Motion/Images.xcassets/grid.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "grid.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "grid@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/WorldFacts/Icon.png b/Motion/Motion/Images.xcassets/grid.imageset/grid.png similarity index 57% rename from WorldFacts/Icon.png rename to Motion/Motion/Images.xcassets/grid.imageset/grid.png index 86f8ee4..e629f0a 100644 Binary files a/WorldFacts/Icon.png and b/Motion/Motion/Images.xcassets/grid.imageset/grid.png differ diff --git a/Motion/Motion/Images.xcassets/grid.imageset/grid@2x.png b/Motion/Motion/Images.xcassets/grid.imageset/grid@2x.png new file mode 100644 index 0000000..80d22db Binary files /dev/null and b/Motion/Motion/Images.xcassets/grid.imageset/grid@2x.png differ diff --git a/Motion/Motion/LaunchScreen.storyboard b/Motion/Motion/LaunchScreen.storyboard new file mode 100644 index 0000000..8235141 --- /dev/null +++ b/Motion/Motion/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Motion/Motion/Motion-Info.plist b/Motion/Motion/Motion-Info.plist new file mode 100644 index 0000000..bcdaf3d --- /dev/null +++ b/Motion/Motion/Motion-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/Motion/Motion/UYLAppDelegate.h b/Motion/Motion/UYLAppDelegate.h new file mode 100644 index 0000000..91eacb1 --- /dev/null +++ b/Motion/Motion/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// Motion +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Motion/Motion/UYLAppDelegate.m b/Motion/Motion/UYLAppDelegate.m new file mode 100644 index 0000000..437b99f --- /dev/null +++ b/Motion/Motion/UYLAppDelegate.m @@ -0,0 +1,38 @@ +// +// UYLAppDelegate.m +// Motion +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +@end diff --git a/Motion/Motion/UYLViewController.h b/Motion/Motion/UYLViewController.h new file mode 100644 index 0000000..b428b81 --- /dev/null +++ b/Motion/Motion/UYLViewController.h @@ -0,0 +1,38 @@ +// +// UYLViewController.h +// Motion +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLViewController : UIViewController + +@end diff --git a/Motion/Motion/UYLViewController.m b/Motion/Motion/UYLViewController.m new file mode 100644 index 0000000..b3fad3b --- /dev/null +++ b/Motion/Motion/UYLViewController.m @@ -0,0 +1,95 @@ +// +// UYLViewController.m +// Motion +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLViewController.h" + +@interface UYLViewController () +@property (weak, nonatomic) IBOutlet UIView *pyramidView; +@end + +@implementation UYLViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"grid"]]; + + CGFloat tilt = 50.0; + UIView *view = self.pyramidView; + while (view) + { + [self addHorizontalTilt:tilt verticalTilt:tilt ToView:view]; + tilt += 10; + view = [view.subviews firstObject]; + } +} + +- (void)addHorizontalTilt:(CGFloat)x verticalTilt:(CGFloat)y ToView:(UIView *)view +{ + UIInterpolatingMotionEffect *xAxis = nil; + UIInterpolatingMotionEffect *yAxis = nil; + + if (x != 0.0) + { + xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; + xAxis.minimumRelativeValue = [NSNumber numberWithFloat:-x]; + xAxis.maximumRelativeValue = [NSNumber numberWithFloat:x]; + } + + if (y != 0.0) + { + yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; + yAxis.minimumRelativeValue = [NSNumber numberWithFloat:-y]; + yAxis.maximumRelativeValue = [NSNumber numberWithFloat:y]; + } + + if (xAxis || yAxis) + { + UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init]; + NSMutableArray *effects = [[NSMutableArray alloc] init]; + if (xAxis) + { + [effects addObject:xAxis]; + } + + if (yAxis) + { + [effects addObject:yAxis]; + } + group.motionEffects = effects; + [view addMotionEffect:group]; + } +} + + +@end diff --git a/Motion/Motion/en.lproj/InfoPlist.strings b/Motion/Motion/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Motion/Motion/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Motion/Motion/main.m b/Motion/Motion/main.m new file mode 100644 index 0000000..78f549e --- /dev/null +++ b/Motion/Motion/main.m @@ -0,0 +1,43 @@ +// +// main.m +// Motion +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/Motion/README b/Motion/README new file mode 100644 index 0000000..3ae9ee8 --- /dev/null +++ b/Motion/README @@ -0,0 +1,10 @@ +======================================================================= +Motion - Adding motion effects to views +Version 1.0 03 January 2013 Initial version. +======================================================================= + +This is a example project showing how to add motion effects to a view +to create a sense of depth. + +For further details see the following blog post: +https://useyourloaf.com/blog/motion-effects/ diff --git a/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..59fec2d --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/Contents.swift @@ -0,0 +1,15 @@ +import UIKit +import PlaygroundSupport +/*: + ### Bottom + + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .bottom +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..161eebd --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Bottom.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..fc978bb --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Bottom Left + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .bottomLeft +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..917c692 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/BottomLeft.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..0446b00 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/Contents.swift @@ -0,0 +1,13 @@ +import UIKit +import PlaygroundSupport +/*: + ### Bottom Right + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .bottomRight +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) diff --git a/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..f0fc782 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/BottomRight.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..0dd5c94 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/Contents.swift @@ -0,0 +1,15 @@ +import UIKit +import PlaygroundSupport +/*: + ### Center + + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .center +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..2bc0857 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Center.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..42e640e --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Left + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .left +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..66dffd5 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Left.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..7449f2c --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/Contents.swift @@ -0,0 +1,18 @@ +import UIKit +import PlaygroundSupport +/*: + ### Redraw + + Use this mode when you have a custom view that implements drawRect. + + When the bounds of the view change the view will be redrawn by + calling drawRect. + */ +let myView = CircleView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.backgroundColor = .white +myView.contentMode = .redraw +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..f2256a4 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Redraw.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..d0b78f7 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Right + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .right +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..ba59fd8 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Right.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..59f558d --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/Contents.swift @@ -0,0 +1,30 @@ +import UIKit +import PlaygroundSupport +/*: + ### Scale Aspect Fill + `ScaleAspectFill` scales the content to totally fill the view maintaining the aspect ratio. This can result in the content being larger than the bounds of the view. + + */ +let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) +containerView.backgroundColor = .red + +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +containerView.addSubview(myView) +myView.center = CGPoint(x: 200, y: 200) + +myView.starImageView.contentMode = .scaleAspectFill +/*: + #### clipToBounds + You will most likely want to have the superview set to clip subviews + to bounds to prevent the scaled view from being visible outside the + super view. + + Try changing the following setting to see the difference. + */ +myView.clipsToBounds = true + +containerView +PlaygroundPage.current.liveView = containerView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..9b06466 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFill.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..e3ffcf6 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Scale Aspect Fit + + `ScaleAspectFit` scales the content to fit the view but maintains the aspect ratio. Any part of the view bounds that is not filled with content is transparent. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .scaleAspectFit +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..d7f00b2 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleAspectFit.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..02b1df7 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/Contents.swift @@ -0,0 +1,17 @@ +import UIKit +import PlaygroundSupport +/*: + ### Scale To Fill + + This is the default mode. + + The image is stretched in both dimensions to fill the frame. The + aspect ratio of the image is not maintained. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .scaleToFill +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..542aa26 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/ScaleToFill.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..0be4c20 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/Contents.swift @@ -0,0 +1,15 @@ +import UIKit +import PlaygroundSupport +/*: + ### Top + + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .top +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..41b8111 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/Top.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..edfb1fe --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Top Left + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .topLeft +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..7be4241 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/TopLeft.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..23c2625 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/Contents.swift @@ -0,0 +1,14 @@ +import UIKit +import PlaygroundSupport +/*: + ### Top Right + Fix the position of the content. Does not scale + or stretch the content. + */ +let myView = StarView(frame: CGRect(x: 0, y: 0, width:200, height:350)) +myView.starImageView.contentMode = .topRight +myView +PlaygroundPage.current.liveView = myView +//: [Previous](@previous) +//: [Index](contentMode) +//: [Next](@next) diff --git a/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/timeline.xctimeline b/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/timeline.xctimeline new file mode 100644 index 0000000..4bdbe79 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/TopRight.xcplaygroundpage/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + + diff --git a/Playgrounds/ContentMode.playground/Pages/contentMode.xcplaygroundpage/Contents.swift b/Playgrounds/ContentMode.playground/Pages/contentMode.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..04412dc --- /dev/null +++ b/Playgrounds/ContentMode.playground/Pages/contentMode.xcplaygroundpage/Contents.swift @@ -0,0 +1,29 @@ +/*: + ### UIView contentMode Quick Guide + +The `contentMode` property of UIView allows you to control how to layout a view when the view's bounds change. The system will not, by default, redraw a view each time the bounds change. That would be wasteful. Instead, depending on the content mode, it can scale, stretch or pin the contents to a fixed position. + + There are thirteen different content modes but it is easiest to think of three main groups based on the effect: + + #### Scaling the View (with or without maintaining the aspect ratio) + ++ [Scale To Fill](ScaleToFill) ++ [Scale Aspect Fit](ScaleAspectFit) ++ [Scale Aspect Fill](ScaleAspectFill) + + #### Redrawing the View + ++ [Redraw](Redraw) + + #### Positioning the View + ++ [Center](Center) ++ [Top](Top) ++ [Bottom](Bottom) ++ [Left](Left) ++ [Right](Right) ++ [TopLeft](TopLeft) ++ [TopRight](TopRight) ++ [BottomLeft](BottomLeft) ++ [BottomRight](BottomRight) +*/ diff --git a/Playgrounds/ContentMode.playground/Resources/star100.png b/Playgrounds/ContentMode.playground/Resources/star100.png new file mode 100644 index 0000000..4965255 Binary files /dev/null and b/Playgrounds/ContentMode.playground/Resources/star100.png differ diff --git a/Playgrounds/ContentMode.playground/Sources/CircleView.swift b/Playgrounds/ContentMode.playground/Sources/CircleView.swift new file mode 100644 index 0000000..fd5c22b --- /dev/null +++ b/Playgrounds/ContentMode.playground/Sources/CircleView.swift @@ -0,0 +1,22 @@ +import UIKit + +public class CircleView: UIView { + + var lineWidth: CGFloat = 5 { + didSet { setNeedsDisplay() } + } + + var color: UIColor = .red { + didSet { setNeedsDisplay() } + } + + public override func draw(_ rect: CGRect) { + + let circleCenter = convert(center, from: superview) + let circleRadius = min(bounds.size.width,bounds.size.height)/2 * 0.80 + let circlePath = UIBezierPath(arcCenter: circleCenter, radius: circleRadius, startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true) + circlePath.lineWidth = lineWidth + color.set() + circlePath.stroke() + } +} diff --git a/Playgrounds/ContentMode.playground/Sources/StarView.swift b/Playgrounds/ContentMode.playground/Sources/StarView.swift new file mode 100644 index 0000000..0fb8775 --- /dev/null +++ b/Playgrounds/ContentMode.playground/Sources/StarView.swift @@ -0,0 +1,21 @@ +import UIKit + +public class StarView: UIView { + + public let starImageView: UIImageView + + public override init(frame: CGRect) { + let starImage = UIImage(named: "star100") + starImageView = UIImageView(image: starImage) + + super.init(frame: frame) + addSubview(starImageView) + backgroundColor = .green + starImageView.frame = bounds + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + diff --git a/Playgrounds/ContentMode.playground/contents.xcplayground b/Playgrounds/ContentMode.playground/contents.xcplayground new file mode 100644 index 0000000..e759d69 --- /dev/null +++ b/Playgrounds/ContentMode.playground/contents.xcplayground @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Playgrounds/ContentMode.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/ContentMode.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5cbf448 --- /dev/null +++ b/Playgrounds/ContentMode.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Playgrounds/ContentMode.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Playgrounds/ContentMode.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Playgrounds/ContentMode.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/QReader/QReader.xcodeproj/project.pbxproj b/QReader/QReader.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a29ccae --- /dev/null +++ b/QReader/QReader.xcodeproj/project.pbxproj @@ -0,0 +1,426 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 5309FFAE19183E2800ADB15A /* UYLTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5309FFAD19183E2800ADB15A /* UYLTextCell.m */; }; + 53249C0419AF6D8400EA1639 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53249C0219AF6D8400EA1639 /* Localizable.strings */; }; + 532884FD19197D6C00E44C28 /* UYLCaptureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532884FC19197D6C00E44C28 /* UYLCaptureViewController.m */; }; + 5344A59918DF769400C61776 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5344A59818DF769400C61776 /* Foundation.framework */; }; + 5344A59B18DF769400C61776 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5344A59A18DF769400C61776 /* CoreGraphics.framework */; }; + 5344A59D18DF769400C61776 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5344A59C18DF769400C61776 /* UIKit.framework */; }; + 5344A5A318DF769400C61776 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5344A5A118DF769400C61776 /* InfoPlist.strings */; }; + 5344A5A518DF769400C61776 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5344A5A418DF769400C61776 /* main.m */; }; + 5344A5A918DF769400C61776 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5344A5A818DF769400C61776 /* UYLAppDelegate.m */; }; + 5344A5AC18DF769400C61776 /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5344A5AA18DF769400C61776 /* Main_iPhone.storyboard */; }; + 5344A5AF18DF769400C61776 /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5344A5AD18DF769400C61776 /* Main_iPad.storyboard */; }; + 5344A5B218DF769400C61776 /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5344A5B118DF769400C61776 /* UYLTableViewController.m */; }; + 5344A5B418DF769400C61776 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5344A5B318DF769400C61776 /* Images.xcassets */; }; + 537EB39F18E231FE006B6FF5 /* UYLWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 537EB39E18E231FE006B6FF5 /* UYLWebViewController.m */; }; + 53B2CD6523C8ED8C007FF91F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53B2CD6723C8ED8C007FF91F /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5309FFAC19183E2800ADB15A /* UYLTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTextCell.h; sourceTree = ""; }; + 5309FFAD19183E2800ADB15A /* UYLTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTextCell.m; sourceTree = ""; }; + 53191C0C1922A774000DCCBB /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; + 53249C0319AF6D8400EA1639 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 532884FB19197D6C00E44C28 /* UYLCaptureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLCaptureViewController.h; sourceTree = ""; }; + 532884FC19197D6C00E44C28 /* UYLCaptureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLCaptureViewController.m; sourceTree = ""; }; + 5344A59518DF769400C61776 /* QReader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QReader.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5344A59818DF769400C61776 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5344A59A18DF769400C61776 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5344A59C18DF769400C61776 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5344A5A018DF769400C61776 /* QReader-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "QReader-Info.plist"; sourceTree = ""; }; + 5344A5A218DF769400C61776 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5344A5A418DF769400C61776 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5344A5A718DF769400C61776 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 5344A5A818DF769400C61776 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 5344A5AB18DF769400C61776 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPhone.storyboard; sourceTree = ""; }; + 5344A5AE18DF769400C61776 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; + 5344A5B018DF769400C61776 /* UYLTableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLTableViewController.h; sourceTree = ""; }; + 5344A5B118DF769400C61776 /* UYLTableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLTableViewController.m; sourceTree = ""; }; + 5344A5B318DF769400C61776 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5344A5BA18DF769400C61776 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 537EB39D18E231FE006B6FF5 /* UYLWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLWebViewController.h; sourceTree = ""; }; + 537EB39E18E231FE006B6FF5 /* UYLWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLWebViewController.m; sourceTree = ""; }; + 53B2CD6623C8ED8C007FF91F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5344A59218DF769400C61776 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5344A59B18DF769400C61776 /* CoreGraphics.framework in Frameworks */, + 5344A59D18DF769400C61776 /* UIKit.framework in Frameworks */, + 5344A59918DF769400C61776 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 532884FE19197D7A00E44C28 /* View */ = { + isa = PBXGroup; + children = ( + 5309FFAC19183E2800ADB15A /* UYLTextCell.h */, + 5309FFAD19183E2800ADB15A /* UYLTextCell.m */, + 5344A5AD18DF769400C61776 /* Main_iPad.storyboard */, + 5344A5AA18DF769400C61776 /* Main_iPhone.storyboard */, + ); + name = View; + sourceTree = ""; + }; + 532884FF19197D8F00E44C28 /* Controller */ = { + isa = PBXGroup; + children = ( + 537EB39D18E231FE006B6FF5 /* UYLWebViewController.h */, + 537EB39E18E231FE006B6FF5 /* UYLWebViewController.m */, + 5344A5B018DF769400C61776 /* UYLTableViewController.h */, + 5344A5B118DF769400C61776 /* UYLTableViewController.m */, + 532884FB19197D6C00E44C28 /* UYLCaptureViewController.h */, + 532884FC19197D6C00E44C28 /* UYLCaptureViewController.m */, + ); + name = Controller; + sourceTree = ""; + }; + 5344A58C18DF769400C61776 = { + isa = PBXGroup; + children = ( + 53191C0C1922A774000DCCBB /* README */, + 5344A59E18DF769400C61776 /* QReader */, + 5344A59718DF769400C61776 /* Frameworks */, + 5344A59618DF769400C61776 /* Products */, + ); + sourceTree = ""; + }; + 5344A59618DF769400C61776 /* Products */ = { + isa = PBXGroup; + children = ( + 5344A59518DF769400C61776 /* QReader.app */, + ); + name = Products; + sourceTree = ""; + }; + 5344A59718DF769400C61776 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5344A59818DF769400C61776 /* Foundation.framework */, + 5344A59A18DF769400C61776 /* CoreGraphics.framework */, + 5344A59C18DF769400C61776 /* UIKit.framework */, + 5344A5BA18DF769400C61776 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5344A59E18DF769400C61776 /* QReader */ = { + isa = PBXGroup; + children = ( + 532884FF19197D8F00E44C28 /* Controller */, + 532884FE19197D7A00E44C28 /* View */, + 5344A5B318DF769400C61776 /* Images.xcassets */, + 5344A59F18DF769400C61776 /* Supporting Files */, + ); + path = QReader; + sourceTree = ""; + }; + 5344A59F18DF769400C61776 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53B2CD6723C8ED8C007FF91F /* LaunchScreen.storyboard */, + 5344A5A718DF769400C61776 /* UYLAppDelegate.h */, + 5344A5A818DF769400C61776 /* UYLAppDelegate.m */, + 5344A5A018DF769400C61776 /* QReader-Info.plist */, + 5344A5A118DF769400C61776 /* InfoPlist.strings */, + 5344A5A418DF769400C61776 /* main.m */, + 53249C0219AF6D8400EA1639 /* Localizable.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5344A59418DF769400C61776 /* QReader */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5344A5CA18DF769400C61776 /* Build configuration list for PBXNativeTarget "QReader" */; + buildPhases = ( + 5344A59118DF769400C61776 /* Sources */, + 5344A59218DF769400C61776 /* Frameworks */, + 5344A59318DF769400C61776 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = QReader; + productName = QReader; + productReference = 5344A59518DF769400C61776 /* QReader.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5344A58D18DF769400C61776 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5344A59418DF769400C61776 = { + DevelopmentTeam = LCC2J94N44; + }; + }; + }; + buildConfigurationList = 5344A59018DF769400C61776 /* Build configuration list for PBXProject "QReader" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5344A58C18DF769400C61776; + productRefGroup = 5344A59618DF769400C61776 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5344A59418DF769400C61776 /* QReader */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5344A59318DF769400C61776 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53249C0419AF6D8400EA1639 /* Localizable.strings in Resources */, + 5344A5AF18DF769400C61776 /* Main_iPad.storyboard in Resources */, + 5344A5B418DF769400C61776 /* Images.xcassets in Resources */, + 53B2CD6523C8ED8C007FF91F /* LaunchScreen.storyboard in Resources */, + 5344A5AC18DF769400C61776 /* Main_iPhone.storyboard in Resources */, + 5344A5A318DF769400C61776 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5344A59118DF769400C61776 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 537EB39F18E231FE006B6FF5 /* UYLWebViewController.m in Sources */, + 5344A5A518DF769400C61776 /* main.m in Sources */, + 5309FFAE19183E2800ADB15A /* UYLTextCell.m in Sources */, + 5344A5A918DF769400C61776 /* UYLAppDelegate.m in Sources */, + 532884FD19197D6C00E44C28 /* UYLCaptureViewController.m in Sources */, + 5344A5B218DF769400C61776 /* UYLTableViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53249C0219AF6D8400EA1639 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 53249C0319AF6D8400EA1639 /* en */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 5344A5A118DF769400C61776 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5344A5A218DF769400C61776 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5344A5AA18DF769400C61776 /* Main_iPhone.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5344A5AB18DF769400C61776 /* Base */, + ); + name = Main_iPhone.storyboard; + sourceTree = ""; + }; + 5344A5AD18DF769400C61776 /* Main_iPad.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5344A5AE18DF769400C61776 /* Base */, + ); + name = Main_iPad.storyboard; + sourceTree = ""; + }; + 53B2CD6723C8ED8C007FF91F /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53B2CD6623C8ED8C007FF91F /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5344A5C818DF769400C61776 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5344A5C918DF769400C61776 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5344A5CB18DF769400C61776 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "QReader/QReader-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5344A5CC18DF769400C61776 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "QReader/QReader-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5344A59018DF769400C61776 /* Build configuration list for PBXProject "QReader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5344A5C818DF769400C61776 /* Debug */, + 5344A5C918DF769400C61776 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5344A5CA18DF769400C61776 /* Build configuration list for PBXNativeTarget "QReader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5344A5CB18DF769400C61776 /* Debug */, + 5344A5CC18DF769400C61776 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5344A58D18DF769400C61776 /* Project object */; +} diff --git a/QReader/QReader/Base.lproj/LaunchScreen.storyboard b/QReader/QReader/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..8b40a2e --- /dev/null +++ b/QReader/QReader/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/QReader/QReader/Base.lproj/Main_iPad.storyboard b/QReader/QReader/Base.lproj/Main_iPad.storyboard new file mode 100644 index 0000000..d0dbadd --- /dev/null +++ b/QReader/QReader/Base.lproj/Main_iPad.storyboard @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/QReader/QReader/Base.lproj/Main_iPhone.storyboard b/QReader/QReader/Base.lproj/Main_iPhone.storyboard new file mode 100644 index 0000000..638b128 --- /dev/null +++ b/QReader/QReader/Base.lproj/Main_iPhone.storyboard @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/Contents.json b/QReader/QReader/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d74362b --- /dev/null +++ b/QReader/QReader/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "qr-40.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "qr-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "qr-58.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "qr-87.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "qr-80.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "qr-120.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "qr-121.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "qr-180.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "qr-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "qr-41.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "qr-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "qr-59.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "qr-42.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "qr-81.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "qr-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "qr-152.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "qr-167.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "qr-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-1024.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-1024.png new file mode 100644 index 0000000..9196262 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-1024.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-120.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-120.png new file mode 100644 index 0000000..2975ebb Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-120.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-121.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-121.png new file mode 100644 index 0000000..2975ebb Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-121.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-152.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-152.png new file mode 100644 index 0000000..4f80346 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-152.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-167.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-167.png new file mode 100644 index 0000000..5e0c3f0 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-167.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-180.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-180.png new file mode 100644 index 0000000..58e642c Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-180.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-20.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-20.png new file mode 100644 index 0000000..6f09da7 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-20.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-29.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-29.png new file mode 100644 index 0000000..6f66886 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-29.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-40.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-40.png new file mode 100644 index 0000000..24450d2 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-40.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-41.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-41.png new file mode 100644 index 0000000..24450d2 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-41.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-42.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-42.png new file mode 100644 index 0000000..24450d2 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-42.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-58.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-58.png new file mode 100644 index 0000000..c87ee92 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-58.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-59.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-59.png new file mode 100644 index 0000000..c87ee92 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-59.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-60.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-60.png new file mode 100644 index 0000000..12e7aa6 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-60.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-76.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-76.png new file mode 100644 index 0000000..628cac9 Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-76.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-80.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-80.png new file mode 100644 index 0000000..ed0910e Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-80.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-81.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-81.png new file mode 100644 index 0000000..ed0910e Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-81.png differ diff --git a/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-87.png b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-87.png new file mode 100644 index 0000000..4052f3d Binary files /dev/null and b/QReader/QReader/Images.xcassets/AppIcon.appiconset/qr-87.png differ diff --git a/QReader/QReader/Images.xcassets/Contents.json b/QReader/QReader/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/QReader/QReader/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/QReader/QReader/QReader-Info.plist b/QReader/QReader/QReader-Info.plist new file mode 100644 index 0000000..b63c730 --- /dev/null +++ b/QReader/QReader/QReader-Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSCameraUsageDescription + The camera is used to capture QR codes. + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main_iPad + UIMainStoryboardFile~ipad + Main_iPad + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + + + diff --git a/QReader/QReader/UYLAppDelegate.h b/QReader/QReader/UYLAppDelegate.h new file mode 100644 index 0000000..6c981b1 --- /dev/null +++ b/QReader/QReader/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/QReader/QReader/UYLAppDelegate.m b/QReader/QReader/UYLAppDelegate.m new file mode 100644 index 0000000..b70acc3 --- /dev/null +++ b/QReader/QReader/UYLAppDelegate.m @@ -0,0 +1,38 @@ +// +// UYLAppDelegate.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +@end diff --git a/QReader/QReader/UYLCaptureViewController.h b/QReader/QReader/UYLCaptureViewController.h new file mode 100644 index 0000000..b48bb41 --- /dev/null +++ b/QReader/QReader/UYLCaptureViewController.h @@ -0,0 +1,37 @@ +// +// UYLCaptureViewController.h +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLCaptureViewController : UIViewController +@end diff --git a/QReader/QReader/UYLCaptureViewController.m b/QReader/QReader/UYLCaptureViewController.m new file mode 100644 index 0000000..879b5d6 --- /dev/null +++ b/QReader/QReader/UYLCaptureViewController.m @@ -0,0 +1,303 @@ +// +// UYLCaptureViewController.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "UYLCaptureViewController.h" +#import "UYLTableViewController.h" + +@interface UYLCaptureViewController () + +@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; +@property (nonatomic, strong) CALayer *targetLayer; +@property (nonatomic, strong) AVCaptureSession *captureSession; +@property (nonatomic, strong) NSMutableArray *codeObjects; + +@end + +@implementation UYLCaptureViewController + +static NSString *UYLSegueToTableView = @"UYLSegueToTableView"; + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +- (NSMutableArray *)codeObjects +{ + if (!_codeObjects) + { + _codeObjects = [NSMutableArray new]; + } + return _codeObjects; +} + +- (AVCaptureSession *)captureSession +{ + if (!_captureSession) + { + NSError *error = nil; + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (device.isAutoFocusRangeRestrictionSupported) + { + if ([device lockForConfiguration:&error]) + { + [device setAutoFocusRangeRestriction:AVCaptureAutoFocusRangeRestrictionNear]; + [device unlockForConfiguration]; + } + } + + // The first time AVCaptureDeviceInput creation will present a dialog to the user + // requesting camera access. If the user refuses the creation fails. + // See WWDC 2013 session #610 for details, but note this behaviour does not seem to + // be enforced on iOS 7 where as it is with iOS 8. + + AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + if (deviceInput) + { + _captureSession = [[AVCaptureSession alloc] init]; + if ([_captureSession canAddInput:deviceInput]) + { + [_captureSession addInput:deviceInput]; + } + + AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init]; + if ([_captureSession canAddOutput:metadataOutput]) + { + [_captureSession addOutput:metadataOutput]; + [metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; + [metadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; + } + + self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession]; + self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + self.previewLayer.frame = self.view.bounds; + [self.view.layer addSublayer:self.previewLayer]; + + self.targetLayer = [CALayer layer]; + self.targetLayer.frame = self.view.bounds; + [self.view.layer addSublayer:self.targetLayer]; + + } + else + { + NSLog(@"Input Device error: %@",[error localizedDescription]); + [self showAlertForCameraError:error]; + } + } + return _captureSession; +} + +#pragma mark - +#pragma mark === View Lifecycle === +#pragma mark - + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + [self startRunning]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self stopRunning]; +} + +- (void)applicationDidEnterBackground:(NSNotification *)notification +{ + [self stopRunning]; +} + +- (void)applicationWillEnterForeground:(NSNotification *)notification +{ + [self startRunning]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - +#pragma mark === Segue === +#pragma mark - + +- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender +{ + if ([identifier isEqualToString:UYLSegueToTableView]) + { + return [self.codeObjects count]; + } + + return NO; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + if ([segue.identifier isEqualToString:UYLSegueToTableView]) + { + UYLTableViewController *viewController = segue.destinationViewController; + viewController.codeObjects = self.codeObjects; + } +} + +#pragma mark - +#pragma mark === AVCaptureMetadataOutputObjectsDelegate === +#pragma mark - + +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection +{ + self.codeObjects = nil; + + for (AVMetadataObject *metadataObject in metadataObjects) + { + AVMetadataObject *transformedObject = [self.previewLayer transformedMetadataObjectForMetadataObject:metadataObject]; + [self.codeObjects addObject:transformedObject]; + } + + [self clearTargetLayer]; + [self showDetectedObjects]; +} + +#pragma mark - +#pragma mark === UIAlertViewDelegate === +#pragma mark - + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == 1) + { + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + [[UIApplication sharedApplication] openURL:url]; + } +} + +#pragma mark - +#pragma mark === Utility methods === +#pragma mark - + +- (void)showAlertForCameraError:(NSError *)error +{ + NSString *buttonTitle = nil; + NSString *message = error.localizedFailureReason ? error.localizedFailureReason : error.localizedDescription; + + if ((error.code == AVErrorApplicationIsNotAuthorizedToUseDevice) && + UIApplicationOpenSettingsURLString) + { + // Starting with iOS 8 we can directly open the settings bundle + // for this App so add a settings button to the alert view. + buttonTitle = NSLocalizedString(@"AlertViewSettingsButton", @"Settings"); + } + + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AlertViewTitleCameraError", @"Camera Error") + message:message + delegate:self + cancelButtonTitle:NSLocalizedString(@"AlertViewCancelButton", @"Cancel") + otherButtonTitles:buttonTitle, nil]; + [alertView show]; +} + +- (void)startRunning +{ + self.codeObjects = nil; + [self.captureSession startRunning]; +} + +- (void)stopRunning +{ + [self.captureSession stopRunning]; + self.captureSession = nil; +} + +- (void)clearTargetLayer +{ + NSArray *sublayers = [[self.targetLayer sublayers] copy]; + for (CALayer *sublayer in sublayers) + { + [sublayer removeFromSuperlayer]; + } +} + +- (void)showDetectedObjects +{ + for (AVMetadataObject *object in self.codeObjects) + { + if ([object isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) + { + CAShapeLayer *shapeLayer = [CAShapeLayer layer]; + shapeLayer.strokeColor = [UIColor redColor].CGColor; + shapeLayer.fillColor = [UIColor clearColor].CGColor; + shapeLayer.lineWidth = 2.0; + shapeLayer.lineJoin = kCALineJoinRound; + CGPathRef path = createPathForPoints([(AVMetadataMachineReadableCodeObject *)object corners]); + shapeLayer.path = path; + CFRelease(path); + [self.targetLayer addSublayer:shapeLayer]; + } + } +} + +CGMutablePathRef createPathForPoints(NSArray* points) +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGPoint point; + + if ([points count] > 0) + { + CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)[points objectAtIndex:0], &point); + CGPathMoveToPoint(path, nil, point.x, point.y); + + int i = 1; + while (i < [points count]) + { + CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)[points objectAtIndex:i], &point); + CGPathAddLineToPoint(path, nil, point.x, point.y); + i++; + } + + CGPathCloseSubpath(path); + } + + return path; +} + +@end diff --git a/QReader/QReader/UYLTableViewController.h b/QReader/QReader/UYLTableViewController.h new file mode 100644 index 0000000..8f9672a --- /dev/null +++ b/QReader/QReader/UYLTableViewController.h @@ -0,0 +1,40 @@ +// +// UYLTableViewController.h +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTableViewController : UITableViewController + +@property (nonatomic, copy) NSArray *codeObjects; + +@end diff --git a/QReader/QReader/UYLTableViewController.m b/QReader/QReader/UYLTableViewController.m new file mode 100644 index 0000000..4e61b68 --- /dev/null +++ b/QReader/QReader/UYLTableViewController.m @@ -0,0 +1,210 @@ +// +// UYLTableViewController.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "UYLTableViewController.h" +#import "UYLWebViewController.h" +#import "UYLTextCell.h" + +@interface UYLTableViewController () + +@property (nonatomic, strong) UYLTextCell *prototypeCell; + +@end + +@implementation UYLTableViewController + +static NSString *UYLTextCellIdentifier = @"UYLTextCell"; +static NSString *UYLSegueToWebView = @"UYLSegueToWebView"; + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +- (UYLTextCell *)prototypeCell +{ + if (!_prototypeCell) + { + _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:UYLTextCellIdentifier]; + } + return _prototypeCell; +} + +#pragma mark - +#pragma mark === View Lifecycle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification object:nil]; +} + +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self.tableView reloadData]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - +#pragma mark === UITableViewDataSource === +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.codeObjects count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:UYLTextCellIdentifier forIndexPath:indexPath]; + [self configureCell:cell forRowAtIndexPath:indexPath]; + return cell; +} + +#pragma mark - +#pragma mark === UITableViewDelegate === +#pragma mark - + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + [self configureCell:self.prototypeCell forRowAtIndexPath:indexPath]; + self.prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds)); + [self.prototypeCell layoutIfNeeded]; + + CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + return size.height+1; +} + +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return UITableViewAutomaticDimension; +} + +#pragma mark - +#pragma mark === Segue === +#pragma mark - + +- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender +{ + BOOL gotLink = NO; + + if ([identifier isEqualToString:UYLSegueToWebView]) + { + NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; + AVMetadataObject *object = [self.codeObjects objectAtIndex:indexPath.row]; + if ([object.type isEqualToString:AVMetadataObjectTypeQRCode]) + { + gotLink = [self codeObjectContainsLink:(AVMetadataMachineReadableCodeObject *)object]; + } + } + + return gotLink; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + if ([segue.identifier isEqualToString:UYLSegueToWebView]) + { + NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; + AVMetadataMachineReadableCodeObject *codeObject = [self.codeObjects objectAtIndex:indexPath.row]; + + UYLWebViewController *viewController = segue.destinationViewController; + viewController.url = [self firstLinkInCodeObject:codeObject]; + } +} + +#pragma mark - +#pragma mark === Utility methods === +#pragma mark - + +- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath +{ + if ([cell isKindOfClass:[UYLTextCell class]]) + { + UYLTextCell *textCell = (UYLTextCell *)cell; + AVMetadataObject *object = [self.codeObjects objectAtIndex:indexPath.row]; + + textCell.valueLabel.text = @"No value"; + textCell.typeLabel.text = object.type; + textCell.accessoryType = UITableViewCellAccessoryNone; + textCell.valueLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + textCell.typeLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; + + if ([object.type isEqualToString:AVMetadataObjectTypeQRCode]) + { + AVMetadataMachineReadableCodeObject *codeObject = (AVMetadataMachineReadableCodeObject *)object; + NSString *stringValue = codeObject.stringValue ? codeObject.stringValue : @"Unable to decode"; + textCell.valueLabel.text = stringValue; + + if ([self codeObjectContainsLink:codeObject]) + { + textCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } + } + } +} + +- (BOOL)codeObjectContainsLink:(AVMetadataMachineReadableCodeObject *)codeObject +{ + NSString *stringValue = codeObject.stringValue; + + NSError *error = nil; + NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error]; + NSUInteger matchCount = [detector numberOfMatchesInString:stringValue options:0 range:NSMakeRange(0, stringValue.length)]; + return (matchCount > 0) ? YES : NO; +} + +- (NSURL *)firstLinkInCodeObject:(AVMetadataMachineReadableCodeObject *)codeObject +{ + NSURL *url = nil; + NSString *stringValue = codeObject.stringValue; + + NSError *error = nil; + NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error]; + NSTextCheckingResult *result = [detector firstMatchInString:stringValue options:0 range:NSMakeRange(0, stringValue.length)]; + if (result.resultType == NSTextCheckingTypeLink) + { + url = result.URL; + } + + return url; +} + +@end diff --git a/QReader/QReader/UYLTextCell.h b/QReader/QReader/UYLTextCell.h new file mode 100644 index 0000000..463d822 --- /dev/null +++ b/QReader/QReader/UYLTextCell.h @@ -0,0 +1,41 @@ +// +// UYLTextCell.h +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTextCell : UITableViewCell + +@property (nonatomic, weak) IBOutlet UILabel *valueLabel; +@property (nonatomic, weak) IBOutlet UILabel *typeLabel; + +@end diff --git a/QReader/QReader/UYLTextCell.m b/QReader/QReader/UYLTextCell.m new file mode 100644 index 0000000..8d4159a --- /dev/null +++ b/QReader/QReader/UYLTextCell.m @@ -0,0 +1,46 @@ +// +// UYLTextCell.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLTextCell.h" + +@implementation UYLTextCell + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + [self.contentView layoutIfNeeded]; + self.valueLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.valueLabel.frame); +} + +@end diff --git a/QReader/QReader/UYLWebViewController.h b/QReader/QReader/UYLWebViewController.h new file mode 100644 index 0000000..220587f --- /dev/null +++ b/QReader/QReader/UYLWebViewController.h @@ -0,0 +1,40 @@ +// +// UYLWebViewController.h +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLWebViewController : UIViewController + +@property (nonatomic, copy) NSURL *url; + +@end diff --git a/QReader/QReader/UYLWebViewController.m b/QReader/QReader/UYLWebViewController.m new file mode 100644 index 0000000..2770718 --- /dev/null +++ b/QReader/QReader/UYLWebViewController.m @@ -0,0 +1,54 @@ +// +// UYLWebViewController.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLWebViewController.h" + +@interface UYLWebViewController () +@property (nonatomic, weak) IBOutlet UIWebView *webView; +@end + +@implementation UYLWebViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = [self.url absoluteString]; + if (self.url) + { + NSURLRequest *request = [NSURLRequest requestWithURL:self.url]; + [self.webView loadRequest:request]; + } +} + +@end diff --git a/QReader/QReader/en.lproj/InfoPlist.strings b/QReader/QReader/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/QReader/QReader/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/QReader/QReader/en.lproj/Localizable.strings b/QReader/QReader/en.lproj/Localizable.strings new file mode 100644 index 0000000..ea0d620 --- /dev/null +++ b/QReader/QReader/en.lproj/Localizable.strings @@ -0,0 +1,11 @@ +/* + Localizable.strings + QReader + + Created by Keith Harrison on 28/08/2014. + Copyright (c) 2014 Keith Harrison. All rights reserved. +*/ + +"AlertViewTitleCameraError" = "Camera Error"; +"AlertViewCancelButton" = "Cancel"; +"AlertViewSettingsButton" = "Settings"; diff --git a/QReader/QReader/main.m b/QReader/QReader/main.m new file mode 100644 index 0000000..17ec1c0 --- /dev/null +++ b/QReader/QReader/main.m @@ -0,0 +1,43 @@ +// +// main.m +// QReader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/QReader/README b/QReader/README new file mode 100644 index 0000000..71a1a9b --- /dev/null +++ b/QReader/README @@ -0,0 +1,14 @@ +======================================================================= +QReader - Reading QR Codes +Version 1.1 28 Aug 2014 Add handling of camera privacys settings. +Version 1.0 12 May 2014 Initial version. +======================================================================= + +Example of how to use AVFoundation to capture QR codes. See the following post for details: + +https://useyourloaf.com/blog/reading-qr-codes/ + +For details on adding an alert view to warn the user when the camera cannot be +accessed and directly launch the settings (requires iOS 8) see the following post: + +https://useyourloaf.com/blog/open-settings-url/ diff --git a/README b/README deleted file mode 100644 index d3200da..0000000 --- a/README +++ /dev/null @@ -1,24 +0,0 @@ -======================================================================= -+ CODE EXAMPLES REPOSITORY - - See http://useyourloaf.com for details - - This README last updated: 06-September-2012 -======================================================================= - -+ INDEX - - AirPrinter - Example of how to print from iOS - AlertView - Demo iOS 5 changes to UIAlertView - MasterSlide - Implementing a mail app style split view controller - NibCollection - Example use of IBOutletCollection - RemindMe - Scheduling local notifications with UILocaNotification - StaticTable - Using a storyboard to implement static table views - SyncMe - Example use of iCloud Key-value Storage - TaskTimer - Example of UIAccessibility Support - TCNibLoad - Example use of UINib class - TwitterSearch - Example of using NSURLConnection to query Twitter API - Stepper - Example use of UIStepper control - Styles - Using UIAppearance proxy to style UIKit controls - WorldFacts - Using storyboards for dynamic table views -======================================================================= \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6d5e16 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +### Code Examples Repository + +See [useyourloaf.com](https://useyourloaf.com) for details. diff --git a/Refresh/README.md b/Refresh/README.md new file mode 100644 index 0000000..793948c --- /dev/null +++ b/Refresh/README.md @@ -0,0 +1,18 @@ +## Refresh - Pull-to-refresh control for a table view controller + + Version 1.2 11 Jan 2020 Update for Xcode 11 + Version 1.1 25 Nov 2016 Update for Xcode 8 and general clean-up. + Version 1.0 18 June 2013 Initial Version + +### Summary + +This Xcode project demonstrates how to implement the pull-to-refresh +control for table views by adding a UIRefreshControl to a table +view controller using Interface Builder. + +This project uses Objective-C and has been updated for compatibility +with Xcode 11. + +For further details see the following post: + ++ [UIRefreshControl Fun and Games](https://useyourloaf.com/blog/uirefreshcontrol-fun-and-games/) diff --git a/Refresh/Refresh.xcodeproj/project.pbxproj b/Refresh/Refresh.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a6839d5 --- /dev/null +++ b/Refresh/Refresh.xcodeproj/project.pbxproj @@ -0,0 +1,351 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 530A6031176F8FBF004F85D9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 530A6030176F8FBF004F85D9 /* UIKit.framework */; }; + 530A6033176F8FBF004F85D9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 530A6032176F8FBF004F85D9 /* Foundation.framework */; }; + 530A6035176F8FBF004F85D9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 530A6034176F8FBF004F85D9 /* CoreGraphics.framework */; }; + 530A603D176F8FBF004F85D9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 530A603C176F8FBF004F85D9 /* main.m */; }; + 530A6041176F8FBF004F85D9 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 530A6040176F8FBF004F85D9 /* UYLAppDelegate.m */; }; + 530A604A176F8FBF004F85D9 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 530A6048176F8FBF004F85D9 /* MainStoryboard.storyboard */; }; + 530A6058176F9081004F85D9 /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 530A6057176F9081004F85D9 /* UYLTableViewController.m */; }; + 53F2D5A21DE8A0CA001851C9 /* DeckDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 53F2D5A11DE8A0CA001851C9 /* DeckDataSource.m */; }; + 53F2D5A91DE8D815001851C9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F2D5AB1DE8D815001851C9 /* LaunchScreen.storyboard */; }; + 53F2D5AD1DE8D86D001851C9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53F2D5AC1DE8D86D001851C9 /* Images.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 530A602D176F8FBF004F85D9 /* Refresh.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Refresh.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 530A6030176F8FBF004F85D9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 530A6032176F8FBF004F85D9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 530A6034176F8FBF004F85D9 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 530A6038176F8FBF004F85D9 /* Refresh-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Refresh-Info.plist"; sourceTree = ""; }; + 530A603C176F8FBF004F85D9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 530A603F176F8FBF004F85D9 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 530A6040176F8FBF004F85D9 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 530A6056176F9081004F85D9 /* UYLTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTableViewController.h; sourceTree = ""; }; + 530A6057176F9081004F85D9 /* UYLTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTableViewController.m; sourceTree = ""; }; + 5332463E177104D400BED81A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; + 53F2D5A01DE8A0CA001851C9 /* DeckDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeckDataSource.h; sourceTree = ""; }; + 53F2D5A11DE8A0CA001851C9 /* DeckDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeckDataSource.m; sourceTree = ""; }; + 53F2D5A61DE8D715001851C9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainStoryboard.storyboard; sourceTree = ""; }; + 53F2D5AA1DE8D815001851C9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53F2D5AC1DE8D86D001851C9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 530A602A176F8FBF004F85D9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 530A6031176F8FBF004F85D9 /* UIKit.framework in Frameworks */, + 530A6033176F8FBF004F85D9 /* Foundation.framework in Frameworks */, + 530A6035176F8FBF004F85D9 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 530A6024176F8FBF004F85D9 = { + isa = PBXGroup; + children = ( + 5332463E177104D400BED81A /* README.md */, + 530A6036176F8FBF004F85D9 /* Refresh */, + 530A602F176F8FBF004F85D9 /* Frameworks */, + 530A602E176F8FBF004F85D9 /* Products */, + ); + sourceTree = ""; + }; + 530A602E176F8FBF004F85D9 /* Products */ = { + isa = PBXGroup; + children = ( + 530A602D176F8FBF004F85D9 /* Refresh.app */, + ); + name = Products; + sourceTree = ""; + }; + 530A602F176F8FBF004F85D9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 530A6030176F8FBF004F85D9 /* UIKit.framework */, + 530A6032176F8FBF004F85D9 /* Foundation.framework */, + 530A6034176F8FBF004F85D9 /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 530A6036176F8FBF004F85D9 /* Refresh */ = { + isa = PBXGroup; + children = ( + 530A6056176F9081004F85D9 /* UYLTableViewController.h */, + 530A6057176F9081004F85D9 /* UYLTableViewController.m */, + 530A603F176F8FBF004F85D9 /* UYLAppDelegate.h */, + 530A6040176F8FBF004F85D9 /* UYLAppDelegate.m */, + 53F2D5A01DE8A0CA001851C9 /* DeckDataSource.h */, + 53F2D5A11DE8A0CA001851C9 /* DeckDataSource.m */, + 530A6048176F8FBF004F85D9 /* MainStoryboard.storyboard */, + 53F2D5AB1DE8D815001851C9 /* LaunchScreen.storyboard */, + 53F2D5AC1DE8D86D001851C9 /* Images.xcassets */, + 530A6037176F8FBF004F85D9 /* Supporting Files */, + ); + path = Refresh; + sourceTree = ""; + }; + 530A6037176F8FBF004F85D9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 530A6038176F8FBF004F85D9 /* Refresh-Info.plist */, + 530A603C176F8FBF004F85D9 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 530A602C176F8FBF004F85D9 /* Refresh */ = { + isa = PBXNativeTarget; + buildConfigurationList = 530A6050176F8FBF004F85D9 /* Build configuration list for PBXNativeTarget "Refresh" */; + buildPhases = ( + 530A6029176F8FBF004F85D9 /* Sources */, + 530A602A176F8FBF004F85D9 /* Frameworks */, + 530A602B176F8FBF004F85D9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Refresh; + productName = Refresh; + productReference = 530A602D176F8FBF004F85D9 /* Refresh.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 530A6025176F8FBF004F85D9 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 530A6028176F8FBF004F85D9 /* Build configuration list for PBXProject "Refresh" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 530A6024176F8FBF004F85D9; + productRefGroup = 530A602E176F8FBF004F85D9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 530A602C176F8FBF004F85D9 /* Refresh */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 530A602B176F8FBF004F85D9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F2D5A91DE8D815001851C9 /* LaunchScreen.storyboard in Resources */, + 53F2D5AD1DE8D86D001851C9 /* Images.xcassets in Resources */, + 530A604A176F8FBF004F85D9 /* MainStoryboard.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 530A6029176F8FBF004F85D9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 530A603D176F8FBF004F85D9 /* main.m in Sources */, + 53F2D5A21DE8A0CA001851C9 /* DeckDataSource.m in Sources */, + 530A6041176F8FBF004F85D9 /* UYLAppDelegate.m in Sources */, + 530A6058176F9081004F85D9 /* UYLTableViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 530A6048176F8FBF004F85D9 /* MainStoryboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F2D5A61DE8D715001851C9 /* Base */, + ); + name = MainStoryboard.storyboard; + sourceTree = ""; + }; + 53F2D5AB1DE8D815001851C9 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F2D5AA1DE8D815001851C9 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 530A604E176F8FBF004F85D9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 530A604F176F8FBF004F85D9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 530A6051176F8FBF004F85D9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = "Refresh/Refresh-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 530A6052176F8FBF004F85D9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_PREFIX_HEADER = ""; + INFOPLIST_FILE = "Refresh/Refresh-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 530A6028176F8FBF004F85D9 /* Build configuration list for PBXProject "Refresh" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 530A604E176F8FBF004F85D9 /* Debug */, + 530A604F176F8FBF004F85D9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 530A6050176F8FBF004F85D9 /* Build configuration list for PBXNativeTarget "Refresh" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 530A6051176F8FBF004F85D9 /* Debug */, + 530A6052176F8FBF004F85D9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 530A6025176F8FBF004F85D9 /* Project object */; +} diff --git a/Refresh/Refresh/Base.lproj/LaunchScreen.storyboard b/Refresh/Refresh/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..b3f8cb1 --- /dev/null +++ b/Refresh/Refresh/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Refresh/Refresh/Base.lproj/MainStoryboard.storyboard b/Refresh/Refresh/Base.lproj/MainStoryboard.storyboard new file mode 100644 index 0000000..c26048a --- /dev/null +++ b/Refresh/Refresh/Base.lproj/MainStoryboard.storyboard @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Refresh/Refresh/DeckDataSource.h b/Refresh/Refresh/DeckDataSource.h new file mode 100644 index 0000000..bb86685 --- /dev/null +++ b/Refresh/Refresh/DeckDataSource.h @@ -0,0 +1,39 @@ +// +// DeckDataSource.h +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface DeckDataSource : NSObject +- (void)shuffle; +@end diff --git a/Refresh/Refresh/DeckDataSource.m b/Refresh/Refresh/DeckDataSource.m new file mode 100644 index 0000000..7c0eb32 --- /dev/null +++ b/Refresh/Refresh/DeckDataSource.m @@ -0,0 +1,96 @@ +// +// DeckDataSource.m +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "DeckDataSource.h" + +@interface DeckDataSource () +@property (nonatomic, strong) NSMutableArray *deck; +@end + +@implementation DeckDataSource + +static const NSUInteger UYL_MAXOBJECTS = 52; + +#pragma mark - +#pragma mark Custom Accessors +#pragma mark - + +- (NSMutableArray *)deck +{ + if (_deck == nil) + { + _deck = [[NSMutableArray alloc] initWithCapacity:UYL_MAXOBJECTS]; + for (NSInteger index = 0; index < UYL_MAXOBJECTS; index++) + { + [_deck insertObject:@(index+1) atIndex:index]; + } + } + return _deck; +} + +#pragma mark - +#pragma mark Public Interface +#pragma mark - + +- (void)shuffle +{ + NSUInteger count = self.deck.count; + + if (count > 1) + { + for (NSUInteger i = count - 1; i > 0; --i) + { + [self.deck exchangeObjectAtIndex:i + withObjectAtIndex:arc4random_uniform((int32_t)(i + 1))]; + } + } +} + +#pragma mark - +#pragma mark UITableViewDataSource +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.deck.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"BasicCell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; + cell.textLabel.text = [NSString stringWithFormat:@"%@", self.deck[indexPath.row]]; + return cell; +} + +@end diff --git a/Refresh/Refresh/Images.xcassets/AppIcon.appiconset/Contents.json b/Refresh/Refresh/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..19882d5 --- /dev/null +++ b/Refresh/Refresh/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Refresh/Refresh/Refresh-Info.plist b/Refresh/Refresh/Refresh-Info.plist new file mode 100644 index 0000000..b202fa6 --- /dev/null +++ b/Refresh/Refresh/Refresh-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.1 + CFBundleSignature + ???? + CFBundleVersion + 2 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + MainStoryboard + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/Refresh/Refresh/UYLAppDelegate.h b/Refresh/Refresh/UYLAppDelegate.h new file mode 100644 index 0000000..fe4d3a0 --- /dev/null +++ b/Refresh/Refresh/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Refresh/Refresh/UYLAppDelegate.m b/Refresh/Refresh/UYLAppDelegate.m new file mode 100644 index 0000000..e70c316 --- /dev/null +++ b/Refresh/Refresh/UYLAppDelegate.m @@ -0,0 +1,43 @@ +// +// UYLAppDelegate.m +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + return YES; +} + +@end diff --git a/Refresh/Refresh/UYLTableViewController.h b/Refresh/Refresh/UYLTableViewController.h new file mode 100644 index 0000000..55763d6 --- /dev/null +++ b/Refresh/Refresh/UYLTableViewController.h @@ -0,0 +1,38 @@ +// +// UYLTableViewController.h +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTableViewController : UITableViewController + +@end diff --git a/Refresh/Refresh/UYLTableViewController.m b/Refresh/Refresh/UYLTableViewController.m new file mode 100644 index 0000000..52bffda --- /dev/null +++ b/Refresh/Refresh/UYLTableViewController.m @@ -0,0 +1,56 @@ +// +// UYLTableViewController.m +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "UYLTableViewController.h" +#import "DeckDataSource.h" + +@interface UYLTableViewController () +@property (nonatomic,strong) DeckDataSource *deckDataSource; +@end + +@implementation UYLTableViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.deckDataSource = [DeckDataSource new]; + self.tableView.dataSource = self.deckDataSource; +} + +- (IBAction)refresh:(UIRefreshControl *)sender { + [self.deckDataSource shuffle]; + [self.tableView reloadData]; + [sender endRefreshing]; +} + +@end diff --git a/Refresh/Refresh/main.m b/Refresh/Refresh/main.m new file mode 100644 index 0000000..46a46ee --- /dev/null +++ b/Refresh/Refresh/main.m @@ -0,0 +1,43 @@ +// +// main.m +// Refresh +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/RefreshScroll/README.md b/RefreshScroll/README.md new file mode 100644 index 0000000..14b278a --- /dev/null +++ b/RefreshScroll/README.md @@ -0,0 +1,9 @@ +An example of adding a refresh control to a scroll view. This uses +the new in iOS 10 refreshControl property of UIScrollView. For +further details see the following post: + ++ [Refresh Control Changes in iOS 10](https://useyourloaf.com/blog/refresh-control-changes-in-ios-10/) + +### Version History + + Version 1.0 27-Nov-2016 Initial Version (Xcode 8, iOS 10) diff --git a/RefreshScroll/RefreshScroll.xcodeproj/project.pbxproj b/RefreshScroll/RefreshScroll.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e56c093 --- /dev/null +++ b/RefreshScroll/RefreshScroll.xcodeproj/project.pbxproj @@ -0,0 +1,360 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 53C353961DEB6CA700E33073 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C353951DEB6CA700E33073 /* AppDelegate.swift */; }; + 53C3539D1DEB6CA700E33073 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53C3539C1DEB6CA700E33073 /* Assets.xcassets */; }; + 53C353A01DEB6CA700E33073 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53C3539E1DEB6CA700E33073 /* LaunchScreen.storyboard */; }; + 53C353A91DEB6D2200E33073 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53C353AB1DEB6D2200E33073 /* Main.storyboard */; }; + 53C353AE1DEB6DB100E33073 /* AdaptiveScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C353AC1DEB6DB100E33073 /* AdaptiveScrollView.swift */; }; + 53C353AF1DEB6DB100E33073 /* SignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C353AD1DEB6DB100E33073 /* SignUpViewController.swift */; }; + 53C353B51DEB735B00E33073 /* UIRefreshControl+UYL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53C353B41DEB735B00E33073 /* UIRefreshControl+UYL.swift */; }; + 53C353B81DEB767F00E33073 /* UIRefreshControl.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53C353BA1DEB767F00E33073 /* UIRefreshControl.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53C353921DEB6CA700E33073 /* RefreshScroll.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RefreshScroll.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53C353951DEB6CA700E33073 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53C3539C1DEB6CA700E33073 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53C3539F1DEB6CA700E33073 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53C353A11DEB6CA700E33073 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53C353AA1DEB6D2200E33073 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53C353AC1DEB6DB100E33073 /* AdaptiveScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdaptiveScrollView.swift; sourceTree = ""; }; + 53C353AD1DEB6DB100E33073 /* SignUpViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignUpViewController.swift; sourceTree = ""; }; + 53C353B21DEB707100E33073 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53C353B41DEB735B00E33073 /* UIRefreshControl+UYL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIRefreshControl+UYL.swift"; sourceTree = ""; }; + 53C353B91DEB767F00E33073 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/UIRefreshControl.strings; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53C3538F1DEB6CA700E33073 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53C353891DEB6CA700E33073 = { + isa = PBXGroup; + children = ( + 53C353B21DEB707100E33073 /* README.md */, + 53C353941DEB6CA700E33073 /* RefreshScroll */, + 53C353931DEB6CA700E33073 /* Products */, + ); + sourceTree = ""; + }; + 53C353931DEB6CA700E33073 /* Products */ = { + isa = PBXGroup; + children = ( + 53C353921DEB6CA700E33073 /* RefreshScroll.app */, + ); + name = Products; + sourceTree = ""; + }; + 53C353941DEB6CA700E33073 /* RefreshScroll */ = { + isa = PBXGroup; + children = ( + 53C353AD1DEB6DB100E33073 /* SignUpViewController.swift */, + 53C353951DEB6CA700E33073 /* AppDelegate.swift */, + 53C353AC1DEB6DB100E33073 /* AdaptiveScrollView.swift */, + 53C353B41DEB735B00E33073 /* UIRefreshControl+UYL.swift */, + 53C353BA1DEB767F00E33073 /* UIRefreshControl.strings */, + 53C3539C1DEB6CA700E33073 /* Assets.xcassets */, + 53C3539E1DEB6CA700E33073 /* LaunchScreen.storyboard */, + 53C353AB1DEB6D2200E33073 /* Main.storyboard */, + 53C353A11DEB6CA700E33073 /* Info.plist */, + ); + path = RefreshScroll; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53C353911DEB6CA700E33073 /* RefreshScroll */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53C353A41DEB6CA700E33073 /* Build configuration list for PBXNativeTarget "RefreshScroll" */; + buildPhases = ( + 53C3538E1DEB6CA700E33073 /* Sources */, + 53C3538F1DEB6CA700E33073 /* Frameworks */, + 53C353901DEB6CA700E33073 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RefreshScroll; + productName = RefreshScroll; + productReference = 53C353921DEB6CA700E33073 /* RefreshScroll.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53C3538A1DEB6CA700E33073 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53C353911DEB6CA700E33073 = { + CreatedOnToolsVersion = 8.1; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53C3538D1DEB6CA700E33073 /* Build configuration list for PBXProject "RefreshScroll" */; + compatibilityVersion = "Xcode 10.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53C353891DEB6CA700E33073; + productRefGroup = 53C353931DEB6CA700E33073 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53C353911DEB6CA700E33073 /* RefreshScroll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53C353901DEB6CA700E33073 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53C353A91DEB6D2200E33073 /* Main.storyboard in Resources */, + 53C353A01DEB6CA700E33073 /* LaunchScreen.storyboard in Resources */, + 53C353B81DEB767F00E33073 /* UIRefreshControl.strings in Resources */, + 53C3539D1DEB6CA700E33073 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53C3538E1DEB6CA700E33073 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53C353B51DEB735B00E33073 /* UIRefreshControl+UYL.swift in Sources */, + 53C353AF1DEB6DB100E33073 /* SignUpViewController.swift in Sources */, + 53C353961DEB6CA700E33073 /* AppDelegate.swift in Sources */, + 53C353AE1DEB6DB100E33073 /* AdaptiveScrollView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53C3539E1DEB6CA700E33073 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53C3539F1DEB6CA700E33073 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 53C353AB1DEB6D2200E33073 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53C353AA1DEB6D2200E33073 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53C353BA1DEB767F00E33073 /* UIRefreshControl.strings */ = { + isa = PBXVariantGroup; + children = ( + 53C353B91DEB767F00E33073 /* Base */, + ); + name = UIRefreshControl.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53C353A21DEB6CA700E33073 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53C353A31DEB6CA700E33073 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53C353A51DEB6CA700E33073 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RefreshScroll/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RefreshScroll; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53C353A61DEB6CA700E33073 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RefreshScroll/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RefreshScroll; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53C3538D1DEB6CA700E33073 /* Build configuration list for PBXProject "RefreshScroll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53C353A21DEB6CA700E33073 /* Debug */, + 53C353A31DEB6CA700E33073 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53C353A41DEB6CA700E33073 /* Build configuration list for PBXNativeTarget "RefreshScroll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53C353A51DEB6CA700E33073 /* Debug */, + 53C353A61DEB6CA700E33073 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53C3538A1DEB6CA700E33073 /* Project object */; +} diff --git a/RefreshScroll/RefreshScroll/AdaptiveScrollView.swift b/RefreshScroll/RefreshScroll/AdaptiveScrollView.swift new file mode 100644 index 0000000..235488e --- /dev/null +++ b/RefreshScroll/RefreshScroll/AdaptiveScrollView.swift @@ -0,0 +1,65 @@ +// +// AdaptiveScrollView.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class AdaptiveScrollView: UIScrollView { + private func setup() { + let defaultCenter = NotificationCenter.default + defaultCenter.addObserver(self, selector: #selector(AdaptiveScrollView.keyboardDidChangeFrame(_:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil) + } + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + @objc func keyboardDidChangeFrame(_ notification: Notification) { + guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue else { + return + } + + let keyboardSize = keyboardFrame.cgRectValue.size + let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0) + adjustContentInsets(contentInsets) + } + + private func adjustContentInsets(_ contentInsets: UIEdgeInsets) { + contentInset = contentInsets + scrollIndicatorInsets = contentInsets + } +} diff --git a/RefreshScroll/RefreshScroll/AppDelegate.swift b/RefreshScroll/RefreshScroll/AppDelegate.swift new file mode 100644 index 0000000..39d6c65 --- /dev/null +++ b/RefreshScroll/RefreshScroll/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// RefreshScroll +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/AppIcon.appiconset/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/BlueSignUp.pdf b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/BlueSignUp.pdf new file mode 100644 index 0000000..66e58de Binary files /dev/null and b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/BlueSignUp.pdf differ diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/Contents.json new file mode 100644 index 0000000..d89ef4f --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUp.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "BlueSignUp.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/BlueSignUp-Selected.pdf b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/BlueSignUp-Selected.pdf new file mode 100644 index 0000000..ad88215 Binary files /dev/null and b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/BlueSignUp-Selected.pdf differ diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/Contents.json new file mode 100644 index 0000000..13d1a37 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/BlueSignUpSelected.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "BlueSignUp-Selected.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Blue/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/Contents.json new file mode 100644 index 0000000..bfe1daf --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "OrangeSignUp.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/OrangeSignUp.pdf b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/OrangeSignUp.pdf new file mode 100644 index 0000000..04fef61 Binary files /dev/null and b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUp.imageset/OrangeSignUp.pdf differ diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/Contents.json b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/Contents.json new file mode 100644 index 0000000..9856c1b --- /dev/null +++ b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "OrangeSignUp-Selected.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/OrangeSignUp-Selected.pdf b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/OrangeSignUp-Selected.pdf new file mode 100644 index 0000000..b18f2d9 Binary files /dev/null and b/RefreshScroll/RefreshScroll/Assets.xcassets/Orange/OrangeSignUpSelected.imageset/OrangeSignUp-Selected.pdf differ diff --git a/RefreshScroll/RefreshScroll/Base.lproj/LaunchScreen.storyboard b/RefreshScroll/RefreshScroll/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..d278eb3 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RefreshScroll/RefreshScroll/Base.lproj/Main.storyboard b/RefreshScroll/RefreshScroll/Base.lproj/Main.storyboard new file mode 100644 index 0000000..ec3b561 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Base.lproj/Main.storyboard @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RefreshScroll/RefreshScroll/Base.lproj/UIRefreshControl.strings b/RefreshScroll/RefreshScroll/Base.lproj/UIRefreshControl.strings new file mode 100644 index 0000000..2f4efdf --- /dev/null +++ b/RefreshScroll/RefreshScroll/Base.lproj/UIRefreshControl.strings @@ -0,0 +1,30 @@ +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +"PullToRefresh" = "Pull to refresh"; diff --git a/RefreshScroll/RefreshScroll/Info.plist b/RefreshScroll/RefreshScroll/Info.plist new file mode 100644 index 0000000..3e33804 --- /dev/null +++ b/RefreshScroll/RefreshScroll/Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/RefreshScroll/RefreshScroll/SignUpViewController.swift b/RefreshScroll/RefreshScroll/SignUpViewController.swift new file mode 100644 index 0000000..3fc53ef --- /dev/null +++ b/RefreshScroll/RefreshScroll/SignUpViewController.swift @@ -0,0 +1,65 @@ +// +// SignUpViewController.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class SignUpViewController: UIViewController { + @IBOutlet private var scrollView: AdaptiveScrollView! + @IBOutlet private var orangeLabel: UILabel! + @IBOutlet private var orangeButton: UIButton! + + private var orangeAvailable = true { + didSet { + orangeLabel.isHidden = !orangeAvailable + orangeButton.isHidden = !orangeAvailable + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + if #available(iOS 10.0, *) { + let refreshControl = UIRefreshControl() + let title = NSLocalizedString("PullToRefresh", comment: "Pull to refresh") + refreshControl.attributedTitle = NSAttributedString(string: title) + refreshControl.addTarget(self, + action: #selector(refreshOptions(sender:)), + for: .valueChanged) + scrollView.refreshControl = refreshControl + } + } + + @objc private func refreshOptions(sender: UIRefreshControl) { + orangeAvailable = !orangeAvailable + sender.endRefreshing() + } +} diff --git a/RefreshScroll/RefreshScroll/UIRefreshControl+UYL.swift b/RefreshScroll/RefreshScroll/UIRefreshControl+UYL.swift new file mode 100644 index 0000000..7394fdc --- /dev/null +++ b/RefreshScroll/RefreshScroll/UIRefreshControl+UYL.swift @@ -0,0 +1,44 @@ +// +// UIRefreshControl+UYL.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +extension UIRefreshControl { + // Example class factory method with preset title + class func uylDefault(target: Any?, action: Selector) -> UIRefreshControl { + let refreshControl = UIRefreshControl() + let title = NSLocalizedString("PullToRefresh", comment: "Pull to refresh") + refreshControl.attributedTitle = NSAttributedString(string: title) + refreshControl.addTarget(target, action: action, for: .valueChanged) + return refreshControl + } +} diff --git a/RemindMe/Classes/RemindMeAppDelegate.h b/RemindMe/Classes/RemindMeAppDelegate.h deleted file mode 100644 index ca22ffd..0000000 --- a/RemindMe/Classes/RemindMeAppDelegate.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// RemindMeAppDelegate.h -// -// Created by Keith Harrison on 12/07/2010 http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import - -@class RemindMeViewController; - -@interface RemindMeAppDelegate : NSObject - -@property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, retain) IBOutlet RemindMeViewController *remindMeViewController; - -extern NSString *kRemindMeNotificationDataKey; - -@end - diff --git a/RemindMe/Classes/RemindMeAppDelegate.m b/RemindMe/Classes/RemindMeAppDelegate.m deleted file mode 100644 index e20515d..0000000 --- a/RemindMe/Classes/RemindMeAppDelegate.m +++ /dev/null @@ -1,87 +0,0 @@ -// -// RemindMeAppDelegate.m -// -// Created by Keith Harrison on 12/07/2010 http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import "RemindMeAppDelegate.h" -#import "RemindMeViewController.h" - -@implementation RemindMeAppDelegate - -NSString *kRemindMeNotificationDataKey = @"kRemindMeNotificationDataKey"; - -#pragma mark - -#pragma mark === Application Delegate Methods === -#pragma mark - - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; - if (notification) - { - NSString *reminderText = [notification.userInfo objectForKey:kRemindMeNotificationDataKey]; - [self.remindMeViewController showReminder:reminderText]; - } - - application.applicationIconBadgeNumber = 0; - - [self.window addSubview:self.remindMeViewController.view]; - [self.window makeKeyAndVisible]; - - return YES; -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - application.applicationIconBadgeNumber = 0; -} - -- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification -{ - // UIApplicationState state = [application applicationState]; - // if (state == UIApplicationStateInactive) { - - // Application was in the background when notification - // was delivered. - // } - - application.applicationIconBadgeNumber = 0; - NSString *reminderText = [notification.userInfo - objectForKey:kRemindMeNotificationDataKey]; - [self.remindMeViewController showReminder:reminderText]; -} - -- (void)dealloc -{ - [_remindMeViewController release]; - [_window release]; - [super dealloc]; -} - -@end diff --git a/RemindMe/Classes/RemindMeViewController.h b/RemindMe/Classes/RemindMeViewController.h deleted file mode 100644 index 686ecfe..0000000 --- a/RemindMe/Classes/RemindMeViewController.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// RemindMeViewController.h -// -// Created by Keith Harrison on 12/07/2010 http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import - -@interface RemindMeViewController : UIViewController - -@property (nonatomic,retain) IBOutlet UITextField *reminderText; -@property (nonatomic,retain) IBOutlet UISegmentedControl *scheduleControl; -@property (nonatomic,retain) IBOutlet UIButton *setButton; -@property (nonatomic,retain) IBOutlet UIButton *clearButton; -@property (nonatomic,retain) IBOutlet UIDatePicker *datePicker; - -- (IBAction)clearNotification; -- (IBAction)scheduleNotification; -- (void)showReminder:(NSString *)text; -@end - diff --git a/RemindMe/Classes/RemindMeViewController.m b/RemindMe/Classes/RemindMeViewController.m deleted file mode 100644 index 82cb231..0000000 --- a/RemindMe/Classes/RemindMeViewController.m +++ /dev/null @@ -1,146 +0,0 @@ -// -// RemindMeViewController.m -// -// Created by Keith Harrison on 12/07/2010 http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import "RemindMeViewController.h" -#import "RemindMeAppDelegate.h" - -@implementation RemindMeViewController - -#pragma mark - -#pragma mark === Initialization and shutdown === -#pragma mark - - -- (void)viewDidLoad -{ - self.datePicker.minimumDate = [NSDate date]; - self.reminderText.delegate = self; -} - -- (void)viewDidUnload -{ - [super viewDidUnload]; - self.reminderText = nil; - self.scheduleControl = nil; - self.clearButton = nil; - self.setButton = nil; - self.datePicker = nil; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation -{ - return NO; -} - -- (void)dealloc -{ - [_reminderText release]; - [_scheduleControl release]; - [_clearButton release]; - [_setButton release]; - [_datePicker release]; - [super dealloc]; -} - -#pragma mark - -#pragma mark === Text Field Delegate === -#pragma mark - - -- (BOOL)textFieldShouldReturn:(UITextField *)textField -{ - [textField resignFirstResponder]; - return YES; -} - -#pragma mark - -#pragma mark === View Actions === -#pragma mark - - -- (void)clearNotification -{ - [[UIApplication sharedApplication] cancelAllLocalNotifications]; -} - -- (void)scheduleNotification -{ - [self.reminderText resignFirstResponder]; - [[UIApplication sharedApplication] cancelAllLocalNotifications]; - - UILocalNotification *notif = [[UILocalNotification alloc] init]; - notif.fireDate = [self.datePicker date]; - notif.timeZone = [NSTimeZone defaultTimeZone]; - - notif.alertBody = @"Did you forget something?"; - notif.alertAction = @"Show me"; - notif.soundName = UILocalNotificationDefaultSoundName; - notif.applicationIconBadgeNumber = 1; - - NSInteger index = [self.scheduleControl selectedSegmentIndex]; - switch (index) - { - case 1: - notif.repeatInterval = NSMinuteCalendarUnit; - break; - case 2: - notif.repeatInterval = NSHourCalendarUnit; - break; - case 3: - notif.repeatInterval = NSDayCalendarUnit; - break; - case 4: - notif.repeatInterval = NSMonthCalendarUnit; - break; - default: - notif.repeatInterval = 0; - break; - } - - NSDictionary *userDict = [NSDictionary dictionaryWithObject:self.reminderText.text - forKey:kRemindMeNotificationDataKey]; - notif.userInfo = userDict; - [[UIApplication sharedApplication] scheduleLocalNotification:notif]; - [notif release]; -} - -#pragma mark - -#pragma mark === Public Methods === -#pragma mark - - -- (void)showReminder:(NSString *)text -{ - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Reminder" - message:text delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alertView show]; - [alertView release]; -} - -@end diff --git a/RemindMe/MainWindow.xib b/RemindMe/MainWindow.xib deleted file mode 100644 index 993b546..0000000 --- a/RemindMe/MainWindow.xib +++ /dev/null @@ -1,329 +0,0 @@ - - - - 1296 - 12B19 - 2549 - 1187 - 624.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1498 - - - YES - IBProxyObject - IBUICustomObject - IBUIViewController - IBUIWindow - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - IBCocoaTouchFramework - - - RemindMeViewController - - - 1 - 1 - - IBCocoaTouchFramework - NO - - - - 292 - {320, 480} - - - - 1 - MSAxIDEAA - - NO - NO - - IBCocoaTouchFramework - YES - - - - - YES - - - delegate - - - - 4 - - - - window - - - - 14 - - - - remindMeViewController - - - - 16 - - - - - YES - - 0 - - YES - - - - - - -1 - - - File's Owner - - - 3 - - - RemindMe App Delegate - - - -2 - - - - - 10 - - - - - 12 - - - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 10.CustomClassName - 10.IBPluginDependency - 12.IBPluginDependency - 3.CustomClassName - 3.IBPluginDependency - - - YES - UIApplication - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RemindMeViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RemindMeAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 16 - - - - YES - - RemindMeAppDelegate - NSObject - - YES - - YES - remindMeViewController - window - - - YES - RemindMeViewController - UIWindow - - - - YES - - YES - remindMeViewController - window - - - YES - - remindMeViewController - RemindMeViewController - - - window - UIWindow - - - - - IBProjectSource - ./Classes/RemindMeAppDelegate.h - - - - RemindMeViewController - UIViewController - - YES - - YES - clearNotification - scheduleNotification - - - YES - id - id - - - - YES - - YES - clearNotification - scheduleNotification - - - YES - - clearNotification - id - - - scheduleNotification - id - - - - - YES - - YES - clearButton - datePicker - reminderText - scheduleControl - setButton - - - YES - UIButton - UIDatePicker - UITextField - UISegmentedControl - UIButton - - - - YES - - YES - clearButton - datePicker - reminderText - scheduleControl - setButton - - - YES - - clearButton - UIButton - - - datePicker - UIDatePicker - - - reminderText - UITextField - - - scheduleControl - UISegmentedControl - - - setButton - UIButton - - - - - IBProjectSource - ./Classes/RemindMeViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 1498 - - diff --git a/RemindMe/README b/RemindMe/README deleted file mode 100644 index 1c341d8..0000000 --- a/RemindMe/README +++ /dev/null @@ -1,18 +0,0 @@ -======================================================================= -RemindMe - -Version 1.0 31 July 2010 Initial release -Version 1.1 06 September 2012 Minor updates to remove iOS 3 support -======================================================================= - -The RemindMe App is a demonstration on how to schedule local notifications -using the UILocalNotification class. The following blog post provides -further details: - -useyourloaf.com/blog/2010/07/31/adding-local-notifications-with-ios-4.html - -Since the original posting the example code has been updated to set the -minimum deployment target to be iOS 4.2. This has allowed some of the code -required to protect from unknown classes when deploying to iOS 3.x to be -removed. This project has been built using Xcode 4.4.1 building with a base SDK of iOS 5.1. It uses manual (non-ARC) based memory management. -======================================================================= \ No newline at end of file diff --git a/RemindMe/RemindMeViewController.xib b/RemindMe/RemindMeViewController.xib deleted file mode 100644 index 65dfd56..0000000 --- a/RemindMe/RemindMeViewController.xib +++ /dev/null @@ -1,768 +0,0 @@ - - - - 1024 - 10F569 - 804 - 1038.29 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 123 - - - YES - - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - YES - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - YES - - - 290 - {{20, 20}, {280, 31}} - - NO - YES - IBCocoaTouchFramework - 0 - - 3 - Enter reminder text - - 3 - MAA - - 2 - - - - Helvetica - 18 - 16 - - YES - 18 - - 2 - 9 - IBCocoaTouchFramework - - 1 - - - - 289 - {{20, 169}, {72, 38}} - - NO - IBCocoaTouchFramework - 0 - 0 - - Helvetica-Bold - 18 - 16 - - 1 - Set - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - - - 289 - {{228, 169}, {72, 38}} - - NO - IBCocoaTouchFramework - 0 - 0 - - 1 - Clear - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - 264 - {{0, 224}, {320, 216}} - - IBCocoaTouchFramework - 0 - 0 - - en_US - - - America/Los_Angeles - - VFppZgAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAC5AAAABAAAABCepkign7sVkKCGKqChmveQ -y4kaoNIj9HDSYSYQ1v50INiArZDa/tGg28CQENzes6DdqayQ3r6VoN+JjpDgnneg4WlwkOJ+WaDjSVKQ -5F47oOUpNJDmR1gg5xJREOgnOiDo8jMQ6gccIOrSFRDr5v4g7LH3EO3G4CDukdkQ76/8oPBxuxDxj96g -8n/BkPNvwKD0X6OQ9U+ioPY/hZD3L4Sg+CiiEPkPZqD6CIQQ+viDIPvoZhD82GUg/chIEP64RyD/qCoQ -AJgpIAGIDBACeAsgA3EokARhJ6AFUQqQBkEJoAcw7JAHjUOgCRDOkAmtvyAK8LCQC+CvoAzZzRANwJGg -DrmvEA+priAQmZEQEYmQIBJ5cxATaXIgFFlVEBVJVCAWOTcQFyk2IBgiU5AZCRggGgI1kBryNKAb4heQ -HNIWoB3B+ZAesfigH6HbkCB2KyAhgb2QIlYNICNq2hAkNe8gJUq8ECYV0SAnKp4QJ/7toCkKgBAp3s+g -KupiECu+saAs036QLZ6ToC6zYJAvfnWgMJNCkDFnkiAycySQM0d0IDRTBpA1J1YgNjLokDcHOCA4HAUQ -OOcaIDn75xA6xvwgO9vJEDywGKA9u6sQPo/6oD+bjRBAb9ygQYSpkEJPvqBDZIuQRC+goEVEbZBF89Mg -Ry2KEEfTtSBJDWwQSbOXIErtThBLnLOgTNZqkE18laBOtkyQT1x3oFCWLpBRPFmgUnYQkFMcO6BUVfKQ -VPwdoFY11JBW5TogWB7xEFjFHCBZ/tMQWqT+IFvetRBchOAgXb6XEF5kwiBfnnkQYE3eoGGHlZBiLcCg -Y2d3kGQNoqBlR1mQZe2EoGcnO5BnzWagaQcdkGmtSKBq5v+Qa5ZlIGzQHBBtdkcgbq/+EG9WKSBwj+AQ -cTYLIHJvwhBzFe0gdE+kEHT/CaB2OMCQdt7roHgYopB4vs2gefiEkHqer6B72GaQfH6RoH24SJB+XnOg -f5gqkAABAAECAwEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA -AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA -AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA -AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBUAAAAAAEAAAABA - - - - 302219427.89499003 - - 5 - - - - 289 - {{11, 100}, {299, 44}} - - NO - IBCocoaTouchFramework - 5 - 0 - - YES - None - m - H - D - W - - - YES - - - - - - - - YES - - - - - - - - YES - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - - - YES - - - - - - - - - - 292 - {{20, 71}, {280, 21}} - - NO - YES - 7 - NO - IBCocoaTouchFramework - Repeat schedule - - 1 - MSAxIDEAA - - - 1 - 10 - - - {320, 460} - - - 1 - MC41IDAgMC41AA - - NO - - IBCocoaTouchFramework - - - - - YES - - - view - - - - 7 - - - - setButton - - - - 16 - - - - scheduleNotification - - - 7 - - 18 - - - - reminderText - - - - 19 - - - - clearNotification - - - 7 - - 21 - - - - clearButton - - - - 22 - - - - datePicker - - - - 24 - - - - scheduleControl - - - - 27 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - YES - - - - - - - - - - - 13 - - - - - 14 - - - - - 20 - - - - - 23 - - - - - 25 - - - - - 26 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 13.IBPluginDependency - 14.IBPluginDependency - 14.IBViewBoundsToFrameTransform - 20.IBPluginDependency - 20.IBViewBoundsToFrameTransform - 23.IBPluginDependency - 25.IBPluginDependency - 25.IBViewBoundsToFrameTransform - 26.IBPluginDependency - 26.IBViewBoundsToFrameTransform - 6.IBEditorWindowLastContentRect - 6.IBPluginDependency - - - YES - RemindMeViewController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABBoAAAw1YAAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABDYwAAw1YAAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABBoAAAwx8AAA - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABBoAAAwsgAAA - - {{620, 208}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - YES - - - - - YES - - - YES - - - - 27 - - - - YES - - RemindMeViewController - UIViewController - - YES - - YES - clearNotification - scheduleNotification - - - YES - id - id - - - - YES - - YES - clearNotification - scheduleNotification - - - YES - - clearNotification - id - - - scheduleNotification - id - - - - - YES - - YES - clearButton - datePicker - reminderText - scheduleControl - setButton - - - YES - UIButton - UIDatePicker - UITextField - UISegmentedControl - UIButton - - - - YES - - YES - clearButton - datePicker - reminderText - scheduleControl - setButton - - - YES - - clearButton - UIButton - - - datePicker - UIDatePicker - - - reminderText - UITextField - - - scheduleControl - UISegmentedControl - - - setButton - UIButton - - - - - IBProjectSource - Classes/RemindMeViewController.h - - - - - YES - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIAccessibility.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UINibLoading.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIResponder.h - - - - UIButton - UIControl - - IBFrameworkSource - UIKit.framework/Headers/UIButton.h - - - - UIControl - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIControl.h - - - - UIDatePicker - UIControl - - IBFrameworkSource - UIKit.framework/Headers/UIDatePicker.h - - - - UILabel - UIView - - IBFrameworkSource - UIKit.framework/Headers/UILabel.h - - - - UIResponder - NSObject - - - - UISearchBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UISearchBar.h - - - - UISearchDisplayController - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UISearchDisplayController.h - - - - UISegmentedControl - UIControl - - IBFrameworkSource - UIKit.framework/Headers/UISegmentedControl.h - - - - UITextField - UIControl - - IBFrameworkSource - UIKit.framework/Headers/UITextField.h - - - - UIView - - - - UIView - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIView.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UINavigationController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UIPopoverController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UISplitViewController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITabBarController.h - - - - UIViewController - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - RemindMe.xcodeproj - 3 - 123 - - diff --git a/RemindMe/RemindMe_Prefix.pch b/RemindMe/RemindMe_Prefix.pch deleted file mode 100644 index c2d3ea2..0000000 --- a/RemindMe/RemindMe_Prefix.pch +++ /dev/null @@ -1,8 +0,0 @@ -// -// Prefix header for all source files of the 'RemindMe' target in the 'RemindMe' project -// - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/RemindMe/main.m b/RemindMe/main.m deleted file mode 100644 index 7fa706f..0000000 --- a/RemindMe/main.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// main.m -// -// Created by Keith Harrison on 12/07/2010 http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import - -int main(int argc, char *argv[]) -{ - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - int retVal = UIApplicationMain(argc, argv, nil, nil); - [pool release]; - return retVal; -} diff --git a/RemindMe10/RemindMe.xcodeproj/project.pbxproj b/RemindMe10/RemindMe.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f91d866 --- /dev/null +++ b/RemindMe10/RemindMe.xcodeproj/project.pbxproj @@ -0,0 +1,497 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 532E65951DB6C89000D63AC8 /* UYLNotificationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532E65941DB6C89000D63AC8 /* UYLNotificationDelegate.swift */; }; + 532E65971DB6CEC300D63AC8 /* UIAlertController+UYLAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532E65961DB6CEC300D63AC8 /* UIAlertController+UYLAlert.swift */; }; + 538B04F61DB55F210085BDA4 /* RemindMeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538B04F51DB55F210085BDA4 /* RemindMeViewController.swift */; }; + 539D5EBD1DC4DBF500130F2F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 539D5EBC1DC4DBF500130F2F /* main.m */; }; + 539D5EC01DC4DBF500130F2F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 539D5EBF1DC4DBF500130F2F /* AppDelegate.m */; }; + 539D5EC61DC4DBF500130F2F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 539D5EC41DC4DBF500130F2F /* Main.storyboard */; }; + 539D5EC81DC4DBF500130F2F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 539D5EC71DC4DBF500130F2F /* Assets.xcassets */; }; + 539D5ECB1DC4DBF500130F2F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 539D5EC91DC4DBF500130F2F /* LaunchScreen.storyboard */; }; + 539D5ED21DC4E0CF00130F2F /* UYLNotificationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 539D5ED11DC4E0CF00130F2F /* UYLNotificationDelegate.m */; }; + 539D5ED51DC4E93000130F2F /* RemindMeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 539D5ED41DC4E93000130F2F /* RemindMeViewController.m */; }; + 539D5ED81DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 539D5ED71DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.m */; }; + 53BA9AF91DB283D7000BD07D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53BA9AF81DB283D7000BD07D /* AppDelegate.swift */; }; + 53BA9AFE1DB283D7000BD07D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BA9AFC1DB283D7000BD07D /* Main.storyboard */; }; + 53BA9B001DB283D7000BD07D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53BA9AFF1DB283D7000BD07D /* Assets.xcassets */; }; + 53BA9B031DB283D7000BD07D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53BA9B011DB283D7000BD07D /* LaunchScreen.storyboard */; }; + 53DE938E1DCBD7F300196391 /* UNMutableNotification+UYL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53DE938D1DCBD7F300196391 /* UNMutableNotification+UYL.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 532E65941DB6C89000D63AC8 /* UYLNotificationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UYLNotificationDelegate.swift; sourceTree = ""; }; + 532E65961DB6CEC300D63AC8 /* UIAlertController+UYLAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertController+UYLAlert.swift"; sourceTree = ""; }; + 538B04F51DB55F210085BDA4 /* RemindMeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemindMeViewController.swift; sourceTree = ""; }; + 539D5EB91DC4DBF500130F2F /* RemindMeObjc.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RemindMeObjc.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 539D5EBC1DC4DBF500130F2F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 539D5EBE1DC4DBF500130F2F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 539D5EBF1DC4DBF500130F2F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 539D5EC51DC4DBF500130F2F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 539D5EC71DC4DBF500130F2F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 539D5ECA1DC4DBF500130F2F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 539D5ECC1DC4DBF500130F2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 539D5ED01DC4E0CF00130F2F /* UYLNotificationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLNotificationDelegate.h; sourceTree = ""; }; + 539D5ED11DC4E0CF00130F2F /* UYLNotificationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLNotificationDelegate.m; sourceTree = ""; }; + 539D5ED31DC4E93000130F2F /* RemindMeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemindMeViewController.h; sourceTree = ""; }; + 539D5ED41DC4E93000130F2F /* RemindMeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemindMeViewController.m; sourceTree = ""; }; + 539D5ED61DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UNMutableNotificationContent+UYLHelper.h"; sourceTree = ""; }; + 539D5ED71DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UNMutableNotificationContent+UYLHelper.m"; sourceTree = ""; }; + 53BA9AF51DB283D7000BD07D /* RemindMe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RemindMe.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53BA9AF81DB283D7000BD07D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53BA9AFD1DB283D7000BD07D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53BA9AFF1DB283D7000BD07D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53BA9B021DB283D7000BD07D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53BA9B041DB283D7000BD07D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53DE938D1DCBD7F300196391 /* UNMutableNotification+UYL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UNMutableNotification+UYL.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 539D5EB61DC4DBF500130F2F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BA9AF21DB283D7000BD07D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 539D5EBA1DC4DBF500130F2F /* RemindMeObjc */ = { + isa = PBXGroup; + children = ( + 539D5EBE1DC4DBF500130F2F /* AppDelegate.h */, + 539D5EBF1DC4DBF500130F2F /* AppDelegate.m */, + 539D5ED31DC4E93000130F2F /* RemindMeViewController.h */, + 539D5ED41DC4E93000130F2F /* RemindMeViewController.m */, + 539D5EC41DC4DBF500130F2F /* Main.storyboard */, + 539D5ED61DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.h */, + 539D5ED71DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.m */, + 539D5EC71DC4DBF500130F2F /* Assets.xcassets */, + 539D5EC91DC4DBF500130F2F /* LaunchScreen.storyboard */, + 539D5ECC1DC4DBF500130F2F /* Info.plist */, + 539D5EBB1DC4DBF500130F2F /* Supporting Files */, + 539D5ED01DC4E0CF00130F2F /* UYLNotificationDelegate.h */, + 539D5ED11DC4E0CF00130F2F /* UYLNotificationDelegate.m */, + ); + path = RemindMeObjc; + sourceTree = ""; + }; + 539D5EBB1DC4DBF500130F2F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 539D5EBC1DC4DBF500130F2F /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53BA9AEC1DB283D7000BD07D = { + isa = PBXGroup; + children = ( + 53BA9AF71DB283D7000BD07D /* RemindMe */, + 539D5EBA1DC4DBF500130F2F /* RemindMeObjc */, + 53BA9AF61DB283D7000BD07D /* Products */, + ); + sourceTree = ""; + }; + 53BA9AF61DB283D7000BD07D /* Products */ = { + isa = PBXGroup; + children = ( + 53BA9AF51DB283D7000BD07D /* RemindMe.app */, + 539D5EB91DC4DBF500130F2F /* RemindMeObjc.app */, + ); + name = Products; + sourceTree = ""; + }; + 53BA9AF71DB283D7000BD07D /* RemindMe */ = { + isa = PBXGroup; + children = ( + 53DE938D1DCBD7F300196391 /* UNMutableNotification+UYL.swift */, + 538B04F51DB55F210085BDA4 /* RemindMeViewController.swift */, + 532E65961DB6CEC300D63AC8 /* UIAlertController+UYLAlert.swift */, + 532E65941DB6C89000D63AC8 /* UYLNotificationDelegate.swift */, + 53BA9AF81DB283D7000BD07D /* AppDelegate.swift */, + 53BA9AFC1DB283D7000BD07D /* Main.storyboard */, + 53BA9AFF1DB283D7000BD07D /* Assets.xcassets */, + 53BA9B011DB283D7000BD07D /* LaunchScreen.storyboard */, + 53BA9B041DB283D7000BD07D /* Info.plist */, + ); + path = RemindMe; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 539D5EB81DC4DBF500130F2F /* RemindMeObjc */ = { + isa = PBXNativeTarget; + buildConfigurationList = 539D5ECF1DC4DBF500130F2F /* Build configuration list for PBXNativeTarget "RemindMeObjc" */; + buildPhases = ( + 539D5EB51DC4DBF500130F2F /* Sources */, + 539D5EB61DC4DBF500130F2F /* Frameworks */, + 539D5EB71DC4DBF500130F2F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RemindMeObjc; + productName = RemindMeObjc; + productReference = 539D5EB91DC4DBF500130F2F /* RemindMeObjc.app */; + productType = "com.apple.product-type.application"; + }; + 53BA9AF41DB283D7000BD07D /* RemindMe */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53BA9B071DB283D7000BD07D /* Build configuration list for PBXNativeTarget "RemindMe" */; + buildPhases = ( + 53BA9AF11DB283D7000BD07D /* Sources */, + 53BA9AF21DB283D7000BD07D /* Frameworks */, + 53BA9AF31DB283D7000BD07D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RemindMe; + productName = RemindMe; + productReference = 53BA9AF51DB283D7000BD07D /* RemindMe.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53BA9AED1DB283D7000BD07D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0800; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 539D5EB81DC4DBF500130F2F = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + 53BA9AF41DB283D7000BD07D = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53BA9AF01DB283D7000BD07D /* Build configuration list for PBXProject "RemindMe" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53BA9AEC1DB283D7000BD07D; + productRefGroup = 53BA9AF61DB283D7000BD07D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53BA9AF41DB283D7000BD07D /* RemindMe */, + 539D5EB81DC4DBF500130F2F /* RemindMeObjc */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 539D5EB71DC4DBF500130F2F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 539D5ECB1DC4DBF500130F2F /* LaunchScreen.storyboard in Resources */, + 539D5EC81DC4DBF500130F2F /* Assets.xcassets in Resources */, + 539D5EC61DC4DBF500130F2F /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BA9AF31DB283D7000BD07D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53BA9B031DB283D7000BD07D /* LaunchScreen.storyboard in Resources */, + 53BA9B001DB283D7000BD07D /* Assets.xcassets in Resources */, + 53BA9AFE1DB283D7000BD07D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 539D5EB51DC4DBF500130F2F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 539D5ED81DC4ECE200130F2F /* UNMutableNotificationContent+UYLHelper.m in Sources */, + 539D5EC01DC4DBF500130F2F /* AppDelegate.m in Sources */, + 539D5EBD1DC4DBF500130F2F /* main.m in Sources */, + 539D5ED21DC4E0CF00130F2F /* UYLNotificationDelegate.m in Sources */, + 539D5ED51DC4E93000130F2F /* RemindMeViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 53BA9AF11DB283D7000BD07D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53DE938E1DCBD7F300196391 /* UNMutableNotification+UYL.swift in Sources */, + 532E65971DB6CEC300D63AC8 /* UIAlertController+UYLAlert.swift in Sources */, + 53BA9AF91DB283D7000BD07D /* AppDelegate.swift in Sources */, + 532E65951DB6C89000D63AC8 /* UYLNotificationDelegate.swift in Sources */, + 538B04F61DB55F210085BDA4 /* RemindMeViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 539D5EC41DC4DBF500130F2F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 539D5EC51DC4DBF500130F2F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 539D5EC91DC4DBF500130F2F /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 539D5ECA1DC4DBF500130F2F /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 53BA9AFC1DB283D7000BD07D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53BA9AFD1DB283D7000BD07D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53BA9B011DB283D7000BD07D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53BA9B021DB283D7000BD07D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 539D5ECD1DC4DBF500130F2F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RemindMeObjc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMeObjc; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 539D5ECE1DC4DBF500130F2F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RemindMeObjc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMeObjc; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 53BA9B051DB283D7000BD07D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53BA9B061DB283D7000BD07D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53BA9B081DB283D7000BD07D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RemindMe/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMe; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53BA9B091DB283D7000BD07D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RemindMe/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RemindMe; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 539D5ECF1DC4DBF500130F2F /* Build configuration list for PBXNativeTarget "RemindMeObjc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 539D5ECD1DC4DBF500130F2F /* Debug */, + 539D5ECE1DC4DBF500130F2F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BA9AF01DB283D7000BD07D /* Build configuration list for PBXProject "RemindMe" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BA9B051DB283D7000BD07D /* Debug */, + 53BA9B061DB283D7000BD07D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53BA9B071DB283D7000BD07D /* Build configuration list for PBXNativeTarget "RemindMe" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53BA9B081DB283D7000BD07D /* Debug */, + 53BA9B091DB283D7000BD07D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53BA9AED1DB283D7000BD07D /* Project object */; +} diff --git a/RemindMe10/RemindMe/AppDelegate.swift b/RemindMe10/RemindMe/AppDelegate.swift new file mode 100644 index 0000000..85e52f5 --- /dev/null +++ b/RemindMe10/RemindMe/AppDelegate.swift @@ -0,0 +1,60 @@ +// +// AppDelegate.swift +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit +import UserNotifications + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + let notificationDelegate = UYLNotificationDelegate() + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + let options: UNAuthorizationOptions = [.alert, .sound]; + registerForLocalNotifications(options: options) + let center = UNUserNotificationCenter.current() + center.delegate = notificationDelegate + notificationDelegate.registerCategories() + return true + } + + private func registerForLocalNotifications(options: UNAuthorizationOptions = [.alert, .sound]) { + let center = UNUserNotificationCenter.current() + center.requestAuthorization(options: options) { (granted, error) in + if !granted { + print("Unable to register") + } + } + } +} diff --git a/RemindMe10/RemindMe/Assets.xcassets/AppIcon.appiconset/Contents.json b/RemindMe10/RemindMe/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/RemindMe10/RemindMe/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RemindMe10/RemindMe/Base.lproj/LaunchScreen.storyboard b/RemindMe10/RemindMe/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/RemindMe10/RemindMe/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RemindMe10/RemindMe/Base.lproj/Main.storyboard b/RemindMe10/RemindMe/Base.lproj/Main.storyboard new file mode 100644 index 0000000..b721145 --- /dev/null +++ b/RemindMe10/RemindMe/Base.lproj/Main.storyboard @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RemindMe10/RemindMe/Info.plist b/RemindMe10/RemindMe/Info.plist new file mode 100644 index 0000000..3e33804 --- /dev/null +++ b/RemindMe10/RemindMe/Info.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/RemindMe10/RemindMe/RemindMeViewController.swift b/RemindMe10/RemindMe/RemindMeViewController.swift new file mode 100644 index 0000000..e2663e1 --- /dev/null +++ b/RemindMe10/RemindMe/RemindMeViewController.swift @@ -0,0 +1,120 @@ +// +// RemindMeViewController.swift +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit +import UserNotifications + +class RemindMeViewController: UIViewController { + + @IBOutlet private weak var reminderText: UITextField! + @IBOutlet private weak var scheduleControl: UISegmentedControl! + @IBOutlet private weak var datePicker: UIDatePicker! + + @IBAction private func scheduleNotification() { + + guard let body = reminderText.text, !body.isEmpty else { + return + } + + clearNotification() + + let content = UNMutableNotificationContent(body: body, title: "Don't forget") + content.categoryIdentifier = UYLNotificationCategory.reminder.rawValue + + // If we want this notification to repeat starting at a future date we schedule + // a non repeating notification at the initial fire date and include + // the repeat interval in the userInfo of the content. + + if let interval = UYLNotificationRepeatInterval(index: scheduleControl.selectedSegmentIndex), + interval != .none { + let userInfo = [UYLNotificationUserDataKey.repeatInterval.rawValue : interval.rawValue] + content.userInfo = userInfo + } + + let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute], from: datePicker.date) + let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false) + + let request = UNNotificationRequest(identifier: UYLNotificationIdentifier.reminder.rawValue, content: content, trigger: trigger) + + UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in + if let error = error { + print(error) + } + self.show(body: body, error: error) + }) + } + + @IBAction private func clearNotification() { + UNUserNotificationCenter.current().removeAllPendingNotificationRequests() + reminderText.resignFirstResponder() + } + + private func show(body: String, error: Error?) { + var alertController: UIAlertController + let title = NSLocalizedString("Scheduled Reminder", comment: "Scheduled Reminder") + if let error = error { + alertController = UIAlertController(title: title, error: error) + } else { + alertController = UIAlertController(title: title, message: body) + } + + DispatchQueue.main.async { + self.present(alertController, animated: true) + } + } + + private func dumpNotifications() { + UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in + for request in requests { + print(request) + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + setupInterface() + } + + private func setupInterface() { + datePicker.minimumDate = Date() + } +} + +extension RemindMeViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } +} diff --git a/RemindMe10/RemindMe/UIAlertController+UYLAlert.swift b/RemindMe10/RemindMe/UIAlertController+UYLAlert.swift new file mode 100644 index 0000000..68db2b6 --- /dev/null +++ b/RemindMe10/RemindMe/UIAlertController+UYLAlert.swift @@ -0,0 +1,47 @@ +// +// UIAlertController+UYLALert.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +extension UIAlertController { + + convenience init(title: String, message: String, okHandler: ((UIAlertAction) -> Void)? = nil) { + self.init(title: title, message: message, preferredStyle: .alert) + let okAction = UIAlertAction(title: NSLocalizedString("OK", comment: "OK Alert Button"), style: .cancel, handler: okHandler) + addAction(okAction) + } + + convenience init(title: String, error: Error, okHandler: ((UIAlertAction) -> Void)? = nil) { + let message = error.localizedDescription + self.init(title: title, message: message, okHandler: okHandler) + } +} diff --git a/RemindMe10/RemindMe/UNMutableNotification+UYL.swift b/RemindMe10/RemindMe/UNMutableNotification+UYL.swift new file mode 100644 index 0000000..8ab4d29 --- /dev/null +++ b/RemindMe10/RemindMe/UNMutableNotification+UYL.swift @@ -0,0 +1,73 @@ +// +// UNMutableNotification+UYL.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UserNotifications + +extension UNMutableNotificationContent { + + /// Create editable content for a user notification. This + /// is a convenience initializer for a simple notification + /// containing a title, body and default sound. + /// + /// - parameters: + /// - body: The message displayed in the notification alert. + /// - title: A short description of the reason for the alert. + /// - sound: The sound to play when the notification is + /// delivered. Defaults to `UNNotificationSound.default`. + + convenience init(body: String, title: String, sound: UNNotificationSound = UNNotificationSound.default) { + self.init() + self.title = NSString.localizedUserNotificationString(forKey: title, arguments: nil) + self.body = body + self.sound = sound + } + + /// Create editiable content for a user notification + /// from the content of an existing notification. + /// + /// - parameters: + /// - content: The content of a local or remote + /// notification. + + convenience init(content: UNNotificationContent) { + self.init() + self.title = content.title + self.subtitle = content.subtitle + self.body = content.body + self.sound = content.sound + self.badge = content.badge + self.launchImageName = content.launchImageName + self.categoryIdentifier = content.categoryIdentifier + self.threadIdentifier = content.threadIdentifier + } +} + diff --git a/RemindMe10/RemindMe/UYLNotificationDelegate.swift b/RemindMe10/RemindMe/UYLNotificationDelegate.swift new file mode 100644 index 0000000..502720a --- /dev/null +++ b/RemindMe10/RemindMe/UYLNotificationDelegate.swift @@ -0,0 +1,143 @@ +// +// UYLNotificationDelegate.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UserNotifications + +enum UYLNotificationIdentifier: String { + case reminder +} + +enum UYLNotificationUserDataKey: String { + case repeatInterval +} + +enum UYLNotificationRepeatInterval: String { + case none + case minute + case hour + case day + case week + + init?(index: Int) { + switch index { + case 0: self = .none + case 1: self = .minute + case 2: self = .hour + case 3: self = .day + case 4: self = .week + default: return nil + } + } +} + +enum UYLNotificationAction: String { + case snooze = "com.useyourloaf.actionSnooze" + case delete = "com.useyourloaf.actionDelete" +} + +enum UYLNotificationCategory: String { + case reminder = "com.useyourloaf.reminder" +} + +class UYLNotificationDelegate: NSObject, UNUserNotificationCenterDelegate { + + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + rescheduleRepeating(notification: notification) + completionHandler([.alert,.sound]) + } + + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { + + switch response.actionIdentifier { + case UNNotificationDismissActionIdentifier: + print("Dismiss Action") + case UNNotificationDefaultActionIdentifier: + print("Default Action") + case UYLNotificationAction.snooze.rawValue: + print("Snooze") + case UYLNotificationAction.delete.rawValue: + print("Delete") + let identifier = response.notification.request.identifier + UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier]) + break + default: + rescheduleRepeating(notification: response.notification) + } + completionHandler() + } + + func registerCategories() { + let snoozeAction = UNNotificationAction(identifier: UYLNotificationAction.snooze.rawValue, title: "Snooze", options: []) + let deleteAction = UNNotificationAction(identifier: UYLNotificationAction.delete.rawValue, title: "Delete", options: [.destructive]) + let category = UNNotificationCategory(identifier: UYLNotificationCategory.reminder.rawValue, actions: [snoozeAction,deleteAction], intentIdentifiers: [], options: []) + UNUserNotificationCenter.current().setNotificationCategories([category]) + } + + private func rescheduleRepeating(notification: UNNotification) { + + let userInfo = notification.request.content.userInfo + let repeatKey = UYLNotificationUserDataKey.repeatInterval.rawValue + + guard let identifier = UYLNotificationIdentifier(rawValue: notification.request.identifier), + identifier == .reminder, + let repeatIntervalRawValue = userInfo[repeatKey] as? String, + let repeatInterval = UYLNotificationRepeatInterval(rawValue: repeatIntervalRawValue), + repeatInterval != .none else { + return + } + + let triggerDate = Calendar.current.dateComponents([.weekday,.day,.hour,.minute], from: notification.date) + + var date = DateComponents() + switch repeatInterval { + case .minute: + date.second = 0 + case .hour: + date.minute = triggerDate.minute + case .day: + date.hour = triggerDate.hour + date.minute = triggerDate.minute + case .week: + date.weekday = triggerDate.weekday + date.hour = triggerDate.hour + date.minute = triggerDate.minute + case .none: + return + } + + let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true) + let content = UNMutableNotificationContent(content: notification.request.content) + let request = UNNotificationRequest(identifier: UYLNotificationIdentifier.reminder.rawValue, content: content, trigger: trigger) + + UNUserNotificationCenter.current().add(request) + } +} diff --git a/RemindMe10/RemindMeObjc/AppDelegate.h b/RemindMe10/RemindMeObjc/AppDelegate.h new file mode 100644 index 0000000..d6e06d6 --- /dev/null +++ b/RemindMe10/RemindMeObjc/AppDelegate.h @@ -0,0 +1,40 @@ +// +// AppDelegate.h +// RemindMeObjc +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end + diff --git a/RemindMe10/RemindMeObjc/AppDelegate.m b/RemindMe10/RemindMeObjc/AppDelegate.m new file mode 100644 index 0000000..c725a0f --- /dev/null +++ b/RemindMe10/RemindMeObjc/AppDelegate.m @@ -0,0 +1,77 @@ +// +// AppDelegate.m +// RemindMeObjc +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +@import UserNotifications; + +#import "AppDelegate.h" +#import "UYLNotificationDelegate.h" + +@interface AppDelegate () +@property (nonatomic,strong) id notificationDelegate; +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [self registerForLocalNotifications]; + self.notificationDelegate = [UYLNotificationDelegate new]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + center.delegate = self.notificationDelegate; + return YES; +} + +- (void)registerForLocalNotifications { + + UNAuthorizationOptions options = UNAuthorizationOptionAlert + UNAuthorizationOptionSound; + UNUserNotificationCenter *center = UNUserNotificationCenter.currentNotificationCenter; + [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (!granted) { + NSLog(@"Something went wrong"); + } + }]; + + UNNotificationAction *snoozeAction = [UNNotificationAction actionWithIdentifier:@"Snooze" title:@"Snooze" options:UNNotificationActionOptionNone]; + UNNotificationAction *deleteAction = [UNNotificationAction actionWithIdentifier:@"Delete" title:@"Delete" options:UNNotificationActionOptionDestructive]; + + UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"UYLReminderCategory" actions:@[snoozeAction,deleteAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone]; + NSSet *categories = [NSSet setWithObject:category]; + [center setNotificationCategories:categories]; + +// let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: []) +// let deleteAction = UNNotificationAction(identifier: UYLNotificationAction.delete.rawValue, title: "Delete", options: [.destructive]) +// let category = UNNotificationCategory(identifier: UYLNotificationCategory.reminder.rawValue, actions: [snoozeAction,deleteAction], intentIdentifiers: [], options: []) +// UNUserNotificationCenter.current().setNotificationCategories([category]) + +} +@end diff --git a/RemindMe10/RemindMeObjc/Assets.xcassets/AppIcon.appiconset/Contents.json b/RemindMe10/RemindMeObjc/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/RemindMe10/RemindMeObjc/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RemindMe10/RemindMeObjc/Base.lproj/LaunchScreen.storyboard b/RemindMe10/RemindMeObjc/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/RemindMe10/RemindMeObjc/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RemindMe10/RemindMeObjc/Base.lproj/Main.storyboard b/RemindMe10/RemindMeObjc/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d193fc6 --- /dev/null +++ b/RemindMe10/RemindMeObjc/Base.lproj/Main.storyboard @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RemindMe10/RemindMeObjc/Info.plist b/RemindMe10/RemindMeObjc/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/RemindMe10/RemindMeObjc/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/RemindMe10/RemindMeObjc/RemindMeViewController.h b/RemindMe10/RemindMeObjc/RemindMeViewController.h new file mode 100644 index 0000000..69ec74a --- /dev/null +++ b/RemindMe10/RemindMeObjc/RemindMeViewController.h @@ -0,0 +1,39 @@ +// +// RemindMeViewController.h +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface RemindMeViewController : UIViewController + +@end diff --git a/RemindMe10/RemindMeObjc/RemindMeViewController.m b/RemindMe10/RemindMeObjc/RemindMeViewController.m new file mode 100644 index 0000000..06b7f5b --- /dev/null +++ b/RemindMe10/RemindMeObjc/RemindMeViewController.m @@ -0,0 +1,105 @@ +// +// RemindMeViewController.m +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "RemindMeViewController.h" +@import UserNotifications; + +@interface RemindMeViewController () +@property (weak, nonatomic) IBOutlet UITextField *reminderText; +@property (weak, nonatomic) IBOutlet UISegmentedControl *scheduleControl; +@property (weak, nonatomic) IBOutlet UIDatePicker *datePicker; +@end + +@implementation RemindMeViewController + +- (IBAction)scheduleNotification { + + if (self.reminderText.text == nil || [self.reminderText.text isEqual:@""]) { + return; + } + + [self clearNotification]; + + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + content.title = @"Don't forget"; + content.body = self.reminderText.text; + content.sound = [UNNotificationSound defaultSound]; + + NSDateComponents *triggerDate = [[NSCalendar currentCalendar] components:NSCalendarUnitYear+NSCalendarUnitMonth+NSCalendarUnitDay+NSCalendarUnitHour+NSCalendarUnitMinute+NSCalendarUnitSecond fromDate:self.datePicker.date]; + UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDate repeats:NO]; + + NSString *identifier = @"UYLLocalNotification"; + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger]; + + [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { + if (error != nil) { + NSLog(@"Something went wrong: %@",error); + } + }]; +} + + +- (IBAction)clearNotification { + [UNUserNotificationCenter.currentNotificationCenter removeAllPendingNotificationRequests]; + [self.reminderText resignFirstResponder]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupInterface]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { + if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) { + // Notifications not allowed + } + }]; +} + +- (void)setupInterface { + self.datePicker.minimumDate = [NSDate date]; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + +@end diff --git a/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.h b/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.h new file mode 100644 index 0000000..fff2fde --- /dev/null +++ b/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.h @@ -0,0 +1,39 @@ +// +// UNMutableNotificationContent+UYLHelper.h +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UNMutableNotificationContent (UYLHelper) + +@end diff --git a/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.m b/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.m new file mode 100644 index 0000000..4277bdf --- /dev/null +++ b/RemindMe10/RemindMeObjc/UNMutableNotificationContent+UYLHelper.m @@ -0,0 +1,48 @@ +// +// UNMutableNotificationContent+UYLHelper.m +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "UNMutableNotificationContent+UYLHelper.h" + +@implementation UNMutableNotificationContent (UYLHelper) + +- (instancetype)initWithBody:(NSString *)body title:(NSString *)title sound:(UNNotificationSound *)sound { + self = [super init]; + if (self) { + self.title = title; + self.body = body; + self.sound = sound; + } + return self; +} +@end diff --git a/RemindMe10/RemindMeObjc/UYLNotificationDelegate.h b/RemindMe10/RemindMeObjc/UYLNotificationDelegate.h new file mode 100644 index 0000000..ea756c7 --- /dev/null +++ b/RemindMe10/RemindMeObjc/UYLNotificationDelegate.h @@ -0,0 +1,40 @@ +// +// UYLNotificationDelegate.h +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +@import UserNotifications; + +@interface UYLNotificationDelegate : NSObject + +@end diff --git a/RemindMe10/RemindMeObjc/UYLNotificationDelegate.m b/RemindMe10/RemindMeObjc/UYLNotificationDelegate.m new file mode 100644 index 0000000..011b8d5 --- /dev/null +++ b/RemindMe10/RemindMeObjc/UYLNotificationDelegate.m @@ -0,0 +1,47 @@ +// +// UYLNotificationDelegate.m +// RemindMe +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLNotificationDelegate.h" + +@implementation UYLNotificationDelegate + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { + completionHandler(UNNotificationPresentationOptionAlert + UNNotificationPresentationOptionSound); +} + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { + completionHandler(); +} + +@end diff --git a/RemindMe10/RemindMeObjc/main.m b/RemindMe10/RemindMeObjc/main.m new file mode 100644 index 0000000..7017275 --- /dev/null +++ b/RemindMe10/RemindMeObjc/main.m @@ -0,0 +1,42 @@ +// +// main.m +// RemindMeObjc +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Restorer/README b/Restorer/README new file mode 100644 index 0000000..7ddd65f --- /dev/null +++ b/Restorer/README @@ -0,0 +1,27 @@ +# Restorer + +The Restorer App demonstrates how to add support for **State Preservation and Restoration** to an iOS App. + +For further details see: + ++ [State Preservation and Restoration](https://useyourloaf.com/blog/state-preservation-and-restoration/ +) + +## License + +The geographic data used in this App is from GeoNames and used under +the Creative Commons Attributions License (see [www.geonames.org](https://www.geonames.org)). + +## Version History + ++ Version 1.3 - 23 Apr 2019 + Update for Xcode 10.2, iOS 12 and WKWebView + ++ Version 1.2 - 01 Jun 2013 + Added checks for bundle version and user interface idiom when restoring. + ++ Version 1.1 - 23 May 2013 + Added example of using a restoration class with a UIWebView + ++ Version 1.0 - 21 May 2013 + Initial Version diff --git a/Restorer/Restorer.xcodeproj/project.pbxproj b/Restorer/Restorer.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c65f8ed --- /dev/null +++ b/Restorer/Restorer.xcodeproj/project.pbxproj @@ -0,0 +1,414 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 531447D3174EBE2400E1AE4F /* UYLWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 531447D2174EBE2400E1AE4F /* UYLWebViewController.m */; }; + 5320FB22225264E200AADA00 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5320FB21225264E200AADA00 /* Images.xcassets */; }; + 5320FB252252655800AADA00 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5320FB232252655800AADA00 /* LaunchScreen.storyboard */; }; + 535CDCD2174C2E440021AE7F /* README in Resources */ = {isa = PBXBuildFile; fileRef = 535CDCD1174C2E440021AE7F /* README */; }; + 535EBE002252692700EEF01D /* UYLWebViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 535EBE022252692700EEF01D /* UYLWebViewController.xib */; }; + 53844B4016F7B2E0007B7561 /* countries.plist in Resources */ = {isa = PBXBuildFile; fileRef = 53844B3F16F7B2E0007B7561 /* countries.plist */; }; + 53844B4316F7B7F0007B7561 /* UYLCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53844B4216F7B7F0007B7561 /* UYLCountryViewController.m */; }; + 53844B4616F7BE98007B7561 /* UYLSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53844B4516F7BE98007B7561 /* UYLSettingsViewController.m */; }; + 53EA99B016F7AE6F0005DF78 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53EA99AF16F7AE6F0005DF78 /* UIKit.framework */; }; + 53EA99B216F7AE6F0005DF78 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53EA99B116F7AE6F0005DF78 /* Foundation.framework */; }; + 53EA99B416F7AE6F0005DF78 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53EA99B316F7AE6F0005DF78 /* CoreGraphics.framework */; }; + 53EA99BA16F7AE6F0005DF78 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53EA99B816F7AE6F0005DF78 /* InfoPlist.strings */; }; + 53EA99BC16F7AE6F0005DF78 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EA99BB16F7AE6F0005DF78 /* main.m */; }; + 53EA99C016F7AE6F0005DF78 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EA99BF16F7AE6F0005DF78 /* UYLAppDelegate.m */; }; + 53EA99C916F7AE6F0005DF78 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53EA99C716F7AE6F0005DF78 /* MainStoryboard.storyboard */; }; + 53EA99E116F7B06A0005DF78 /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EA99E016F7B06A0005DF78 /* UYLTableViewController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 531447D1174EBE2400E1AE4F /* UYLWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLWebViewController.h; sourceTree = ""; }; + 531447D2174EBE2400E1AE4F /* UYLWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLWebViewController.m; sourceTree = ""; }; + 5320FB202252630D00AADA00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainStoryboard.storyboard; sourceTree = ""; }; + 5320FB21225264E200AADA00 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5320FB242252655800AADA00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 535CDCD1174C2E440021AE7F /* README */ = {isa = PBXFileReference; explicitFileType = net.daringfireball.markdown; fileEncoding = 4; path = README; sourceTree = ""; }; + 535EBE012252692700EEF01D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UYLWebViewController.xib; sourceTree = ""; }; + 53844B3F16F7B2E0007B7561 /* countries.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = countries.plist; sourceTree = ""; }; + 53844B4116F7B7F0007B7561 /* UYLCountryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLCountryViewController.h; sourceTree = ""; }; + 53844B4216F7B7F0007B7561 /* UYLCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLCountryViewController.m; sourceTree = ""; }; + 53844B4416F7BE98007B7561 /* UYLSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLSettingsViewController.h; sourceTree = ""; }; + 53844B4516F7BE98007B7561 /* UYLSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLSettingsViewController.m; sourceTree = ""; }; + 53EA99AC16F7AE6F0005DF78 /* Restorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Restorer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53EA99AF16F7AE6F0005DF78 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 53EA99B116F7AE6F0005DF78 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 53EA99B316F7AE6F0005DF78 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 53EA99B716F7AE6F0005DF78 /* Restorer-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Restorer-Info.plist"; sourceTree = ""; }; + 53EA99B916F7AE6F0005DF78 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 53EA99BB16F7AE6F0005DF78 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53EA99BD16F7AE6F0005DF78 /* Restorer-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Restorer-Prefix.pch"; sourceTree = ""; }; + 53EA99BE16F7AE6F0005DF78 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 53EA99BF16F7AE6F0005DF78 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 53EA99DF16F7B06A0005DF78 /* UYLTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTableViewController.h; sourceTree = ""; }; + 53EA99E016F7B06A0005DF78 /* UYLTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTableViewController.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53EA99A916F7AE6F0005DF78 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 53EA99B016F7AE6F0005DF78 /* UIKit.framework in Frameworks */, + 53EA99B216F7AE6F0005DF78 /* Foundation.framework in Frameworks */, + 53EA99B416F7AE6F0005DF78 /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53EA99A316F7AE6F0005DF78 = { + isa = PBXGroup; + children = ( + 535CDCD1174C2E440021AE7F /* README */, + 53EA99B516F7AE6F0005DF78 /* Restorer */, + 53EA99AE16F7AE6F0005DF78 /* Frameworks */, + 53EA99AD16F7AE6F0005DF78 /* Products */, + ); + sourceTree = ""; + }; + 53EA99AD16F7AE6F0005DF78 /* Products */ = { + isa = PBXGroup; + children = ( + 53EA99AC16F7AE6F0005DF78 /* Restorer.app */, + ); + name = Products; + sourceTree = ""; + }; + 53EA99AE16F7AE6F0005DF78 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 53EA99AF16F7AE6F0005DF78 /* UIKit.framework */, + 53EA99B116F7AE6F0005DF78 /* Foundation.framework */, + 53EA99B316F7AE6F0005DF78 /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 53EA99B516F7AE6F0005DF78 /* Restorer */ = { + isa = PBXGroup; + children = ( + 53EA99DE16F7B03B0005DF78 /* Controllers */, + 53EA99DD16F7B0290005DF78 /* Resources */, + 53EA99BE16F7AE6F0005DF78 /* UYLAppDelegate.h */, + 53EA99BF16F7AE6F0005DF78 /* UYLAppDelegate.m */, + 5320FB21225264E200AADA00 /* Images.xcassets */, + 53EA99B616F7AE6F0005DF78 /* Supporting Files */, + ); + path = Restorer; + sourceTree = ""; + }; + 53EA99B616F7AE6F0005DF78 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53EA99B716F7AE6F0005DF78 /* Restorer-Info.plist */, + 53EA99B816F7AE6F0005DF78 /* InfoPlist.strings */, + 53EA99BB16F7AE6F0005DF78 /* main.m */, + 53EA99BD16F7AE6F0005DF78 /* Restorer-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53EA99DD16F7B0290005DF78 /* Resources */ = { + isa = PBXGroup; + children = ( + 535EBE022252692700EEF01D /* UYLWebViewController.xib */, + 53844B3F16F7B2E0007B7561 /* countries.plist */, + 53EA99C716F7AE6F0005DF78 /* MainStoryboard.storyboard */, + 5320FB232252655800AADA00 /* LaunchScreen.storyboard */, + ); + name = Resources; + sourceTree = ""; + }; + 53EA99DE16F7B03B0005DF78 /* Controllers */ = { + isa = PBXGroup; + children = ( + 53EA99DF16F7B06A0005DF78 /* UYLTableViewController.h */, + 53EA99E016F7B06A0005DF78 /* UYLTableViewController.m */, + 53844B4116F7B7F0007B7561 /* UYLCountryViewController.h */, + 53844B4216F7B7F0007B7561 /* UYLCountryViewController.m */, + 53844B4416F7BE98007B7561 /* UYLSettingsViewController.h */, + 53844B4516F7BE98007B7561 /* UYLSettingsViewController.m */, + 531447D1174EBE2400E1AE4F /* UYLWebViewController.h */, + 531447D2174EBE2400E1AE4F /* UYLWebViewController.m */, + ); + name = Controllers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53EA99AB16F7AE6F0005DF78 /* Restorer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53EA99DA16F7AE6F0005DF78 /* Build configuration list for PBXNativeTarget "Restorer" */; + buildPhases = ( + 53EA99A816F7AE6F0005DF78 /* Sources */, + 53EA99A916F7AE6F0005DF78 /* Frameworks */, + 53EA99AA16F7AE6F0005DF78 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Restorer; + productName = Restorer; + productReference = 53EA99AC16F7AE6F0005DF78 /* Restorer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53EA99A416F7AE6F0005DF78 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53EA99AB16F7AE6F0005DF78 = { + DevelopmentTeam = LCC2J94N44; + }; + }; + }; + buildConfigurationList = 53EA99A716F7AE6F0005DF78 /* Build configuration list for PBXProject "Restorer" */; + compatibilityVersion = "Xcode 10.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53EA99A316F7AE6F0005DF78; + productRefGroup = 53EA99AD16F7AE6F0005DF78 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53EA99AB16F7AE6F0005DF78 /* Restorer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53EA99AA16F7AE6F0005DF78 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53EA99BA16F7AE6F0005DF78 /* InfoPlist.strings in Resources */, + 5320FB22225264E200AADA00 /* Images.xcassets in Resources */, + 53EA99C916F7AE6F0005DF78 /* MainStoryboard.storyboard in Resources */, + 53844B4016F7B2E0007B7561 /* countries.plist in Resources */, + 535CDCD2174C2E440021AE7F /* README in Resources */, + 5320FB252252655800AADA00 /* LaunchScreen.storyboard in Resources */, + 535EBE002252692700EEF01D /* UYLWebViewController.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53EA99A816F7AE6F0005DF78 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53EA99BC16F7AE6F0005DF78 /* main.m in Sources */, + 53EA99C016F7AE6F0005DF78 /* UYLAppDelegate.m in Sources */, + 53EA99E116F7B06A0005DF78 /* UYLTableViewController.m in Sources */, + 53844B4316F7B7F0007B7561 /* UYLCountryViewController.m in Sources */, + 53844B4616F7BE98007B7561 /* UYLSettingsViewController.m in Sources */, + 531447D3174EBE2400E1AE4F /* UYLWebViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5320FB232252655800AADA00 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5320FB242252655800AADA00 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; + 535EBE022252692700EEF01D /* UYLWebViewController.xib */ = { + isa = PBXVariantGroup; + children = ( + 535EBE012252692700EEF01D /* Base */, + ); + name = UYLWebViewController.xib; + sourceTree = ""; + }; + 53EA99B816F7AE6F0005DF78 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53EA99B916F7AE6F0005DF78 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 53EA99C716F7AE6F0005DF78 /* MainStoryboard.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5320FB202252630D00AADA00 /* Base */, + ); + name = MainStoryboard.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53EA99D816F7AE6F0005DF78 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 53EA99D916F7AE6F0005DF78 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53EA99DB16F7AE6F0005DF78 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Restorer/Restorer-Prefix.pch"; + INFOPLIST_FILE = "Restorer/Restorer-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 53EA99DC16F7AE6F0005DF78 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Restorer/Restorer-Prefix.pch"; + INFOPLIST_FILE = "Restorer/Restorer-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53EA99A716F7AE6F0005DF78 /* Build configuration list for PBXProject "Restorer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53EA99D816F7AE6F0005DF78 /* Debug */, + 53EA99D916F7AE6F0005DF78 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53EA99DA16F7AE6F0005DF78 /* Build configuration list for PBXNativeTarget "Restorer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53EA99DB16F7AE6F0005DF78 /* Debug */, + 53EA99DC16F7AE6F0005DF78 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53EA99A416F7AE6F0005DF78 /* Project object */; +} diff --git a/Restorer/Restorer/Base.lproj/LaunchScreen.storyboard b/Restorer/Restorer/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..a6e1b7e --- /dev/null +++ b/Restorer/Restorer/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Restorer/Restorer/Base.lproj/MainStoryboard.storyboard b/Restorer/Restorer/Base.lproj/MainStoryboard.storyboard new file mode 100644 index 0000000..139c642 --- /dev/null +++ b/Restorer/Restorer/Base.lproj/MainStoryboard.storyboard @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Restorer/Restorer/Base.lproj/UYLWebViewController.xib b/Restorer/Restorer/Base.lproj/UYLWebViewController.xib new file mode 100644 index 0000000..d33cff2 --- /dev/null +++ b/Restorer/Restorer/Base.lproj/UYLWebViewController.xib @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Restorer/Restorer/Images.xcassets/AppIcon.appiconset/Contents.json b/Restorer/Restorer/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..19882d5 --- /dev/null +++ b/Restorer/Restorer/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Restorer/Restorer/Images.xcassets/Contents.json b/Restorer/Restorer/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Restorer/Restorer/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Restorer/Restorer/Images.xcassets/first.imageset/Contents.json b/Restorer/Restorer/Images.xcassets/first.imageset/Contents.json new file mode 100644 index 0000000..4c4d062 --- /dev/null +++ b/Restorer/Restorer/Images.xcassets/first.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "first@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Restorer/Restorer/Images.xcassets/first.imageset/first.png b/Restorer/Restorer/Images.xcassets/first.imageset/first.png new file mode 100644 index 0000000..9300ee2 Binary files /dev/null and b/Restorer/Restorer/Images.xcassets/first.imageset/first.png differ diff --git a/Restorer/Restorer/Images.xcassets/first.imageset/first@2x.png b/Restorer/Restorer/Images.xcassets/first.imageset/first@2x.png new file mode 100644 index 0000000..374d78e Binary files /dev/null and b/Restorer/Restorer/Images.xcassets/first.imageset/first@2x.png differ diff --git a/Restorer/Restorer/Images.xcassets/second.imageset/Contents.json b/Restorer/Restorer/Images.xcassets/second.imageset/Contents.json new file mode 100644 index 0000000..044ce4b --- /dev/null +++ b/Restorer/Restorer/Images.xcassets/second.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "second@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Restorer/Restorer/Images.xcassets/second.imageset/second.png b/Restorer/Restorer/Images.xcassets/second.imageset/second.png new file mode 100644 index 0000000..1100b48 Binary files /dev/null and b/Restorer/Restorer/Images.xcassets/second.imageset/second.png differ diff --git a/Restorer/Restorer/Images.xcassets/second.imageset/second@2x.png b/Restorer/Restorer/Images.xcassets/second.imageset/second@2x.png new file mode 100644 index 0000000..368d38f Binary files /dev/null and b/Restorer/Restorer/Images.xcassets/second.imageset/second@2x.png differ diff --git a/Restorer/Restorer/Restorer-Info.plist b/Restorer/Restorer/Restorer-Info.plist new file mode 100644 index 0000000..16c34dd --- /dev/null +++ b/Restorer/Restorer/Restorer-Info.plist @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.3 + CFBundleSignature + ???? + CFBundleVersion + 3 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + MainStoryboard + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Restorer/Restorer/Restorer-Prefix.pch b/Restorer/Restorer/Restorer-Prefix.pch new file mode 100644 index 0000000..81517f2 --- /dev/null +++ b/Restorer/Restorer/Restorer-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'Restorer' target in the 'Restorer' project +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Restorer/Restorer/UYLAppDelegate.h b/Restorer/Restorer/UYLAppDelegate.h new file mode 100644 index 0000000..fa61871 --- /dev/null +++ b/Restorer/Restorer/UYLAppDelegate.h @@ -0,0 +1,42 @@ +// +// UYLAppDelegate.h +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +extern NSString *kUYLSettingsAmazingKey; + +@end diff --git a/Restorer/Restorer/UYLAppDelegate.m b/Restorer/Restorer/UYLAppDelegate.m new file mode 100644 index 0000000..8c9ed4c --- /dev/null +++ b/Restorer/Restorer/UYLAppDelegate.m @@ -0,0 +1,104 @@ +// +// UYLAppDelegate.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +NSString *kUYLSettingsAmazingKey = @"amazing"; + +#define BUNDLEMINVERSION 3 + +// Common initilisation code for backward compatibility with iOS 5 +- (void)commonFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kUYLSettingsAmazingKey, + nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; + }); +} + +// Called before state restoration is performed +- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + [self commonFinishLaunchingWithOptions:launchOptions]; + return YES; +} + +// Called after state restortation is performed +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + [self commonFinishLaunchingWithOptions:launchOptions]; + return YES; +} + +// Opt-in to state preservation +- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder +{ + return YES; +} + +// Opt-in to state restoration +- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder +{ + // Retrieve the Bundle Version Key so we can check if the restoration data is from an older + // version of the App that would not make sense to restore. This might be the case after we + // have made significant changes to the view hierarchy. + + NSString *restorationBundleVersion = [coder decodeObjectForKey:UIApplicationStateRestorationBundleVersionKey]; + if ([restorationBundleVersion integerValue] < BUNDLEMINVERSION) + { + NSLog(@"Ignoring restoration data for bundle version: %@",restorationBundleVersion); + return NO; + } + + // Retrieve the User Interface Idiom (iPhone or iPad) for the device that created the restoration Data. + // This allows us to ignore the restoration data when the user interface idiom that created the data + // does not match the current device user interface idiom. + + UIDevice *currentDevice = [UIDevice currentDevice]; + UIUserInterfaceIdiom restorationInterfaceIdiom = [[coder decodeObjectForKey:UIApplicationStateRestorationUserInterfaceIdiomKey] integerValue]; + UIUserInterfaceIdiom currentInterfaceIdiom = currentDevice.userInterfaceIdiom; + if (restorationInterfaceIdiom != currentInterfaceIdiom) + { + NSLog(@"Ignoring restoration data for interface idiom: %ld",(long)restorationInterfaceIdiom); + return NO; + } + + return YES; +} + +@end diff --git a/Restorer/Restorer/UYLCountryViewController.h b/Restorer/Restorer/UYLCountryViewController.h new file mode 100644 index 0000000..76479c0 --- /dev/null +++ b/Restorer/Restorer/UYLCountryViewController.h @@ -0,0 +1,40 @@ +// +// UYLCountryViewController.h +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLCountryViewController : UIViewController + +@property (nonatomic, copy) NSString *capital; + +@end diff --git a/Restorer/Restorer/UYLCountryViewController.m b/Restorer/Restorer/UYLCountryViewController.m new file mode 100644 index 0000000..3877603 --- /dev/null +++ b/Restorer/Restorer/UYLCountryViewController.m @@ -0,0 +1,70 @@ +// +// UYLCountryViewController.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLCountryViewController.h" + +@interface UYLCountryViewController () +@property (weak, nonatomic) IBOutlet UILabel *capitalLabel; +@end + +@implementation UYLCountryViewController + +static NSString *UYLKeyCapital = @"UYLKeyCapital"; + +#pragma mark - +#pragma mark === View Life Cycle Management === +#pragma mark - + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + self.capitalLabel.text = self.capital; +} + +#pragma mark - +#pragma mark === State Restoration === +#pragma mark - + +- (void)encodeRestorableStateWithCoder:(NSCoder *)coder +{ + [coder encodeObject:self.capital forKey:UYLKeyCapital]; + [super encodeRestorableStateWithCoder:coder]; +} + +- (void)decodeRestorableStateWithCoder:(NSCoder *)coder +{ + self.capital = [coder decodeObjectForKey:UYLKeyCapital]; + [super decodeRestorableStateWithCoder:coder]; +} + +@end diff --git a/Restorer/Restorer/UYLSettingsViewController.h b/Restorer/Restorer/UYLSettingsViewController.h new file mode 100644 index 0000000..8cc3bad --- /dev/null +++ b/Restorer/Restorer/UYLSettingsViewController.h @@ -0,0 +1,38 @@ +// +// UYLTextViewController.h +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLSettingsViewController : UIViewController + +@end diff --git a/Restorer/Restorer/UYLSettingsViewController.m b/Restorer/Restorer/UYLSettingsViewController.m new file mode 100644 index 0000000..c5b184f --- /dev/null +++ b/Restorer/Restorer/UYLSettingsViewController.m @@ -0,0 +1,79 @@ +// +// UYLTextViewController.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLSettingsViewController.h" +#import "UYLWebViewController.h" +#import "UYLAppDelegate.h" + +@interface UYLSettingsViewController () +@property (nonatomic, weak) IBOutlet UISwitch *amazingSwitch; +@end + +@implementation UYLSettingsViewController + +#pragma mark - +#pragma mark === View Life Cycle Management === +#pragma mark - + +- (void)viewDidLoad +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + self.amazingSwitch.on = [defaults boolForKey:kUYLSettingsAmazingKey]; +} + +- (void)didDismissPresentedView +{ + [self.presentedViewController dismissViewControllerAnimated:YES completion:NULL]; +} + +#pragma mark - +#pragma mark === Target-Actions === +#pragma mark - + +- (IBAction)amazingAction +{ + BOOL amazingEnabled = self.amazingSwitch.isOn; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:amazingEnabled forKey:kUYLSettingsAmazingKey]; +} + +- (IBAction)pushMe +{ + UYLWebViewController *wvc = [[UYLWebViewController alloc] initWithNibName:@"UYLWebViewController" bundle:nil]; + wvc.restorationIdentifier = @"UYLWebViewController"; + wvc.restorationClass = [UYLWebViewController class]; + wvc.urlString = @"https://useyourloaf.com"; + [self.navigationController showViewController:wvc sender:self]; +} + +@end diff --git a/Restorer/Restorer/UYLTableViewController.h b/Restorer/Restorer/UYLTableViewController.h new file mode 100644 index 0000000..9fbb8ee --- /dev/null +++ b/Restorer/Restorer/UYLTableViewController.h @@ -0,0 +1,38 @@ +// +// UYLTableViewController.h +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLTableViewController : UITableViewController + +@end diff --git a/Restorer/Restorer/UYLTableViewController.m b/Restorer/Restorer/UYLTableViewController.m new file mode 100644 index 0000000..50c6ffc --- /dev/null +++ b/Restorer/Restorer/UYLTableViewController.m @@ -0,0 +1,132 @@ +// +// UYLTableViewController.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLTableViewController.h" +#import "UYLCountryViewController.h" + +@interface UYLTableViewController () +@property (strong, nonatomic) NSArray *worldData; +@end + +@implementation UYLTableViewController + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +- (NSArray *)worldData +{ + NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"countries" ofType:@"plist"]; + NSArray *countries = [[NSArray alloc] initWithContentsOfFile:plistPath]; + return countries; +} + +#pragma mark - +#pragma mark === View Life Cycle Management === +#pragma mark - + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + static NSString *UYLSegueShowCountry = @"UYLSegueShowCountry"; + + if ([segue.identifier isEqualToString:UYLSegueShowCountry]) + { + NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; + NSDictionary *country = [self.worldData objectAtIndex:indexPath.row]; + + UYLCountryViewController *viewController = segue.destinationViewController; + viewController.capital = [country valueForKey:@"capital"]; + } +} + +#pragma mark - +#pragma mark === UITableViewDataSource Delegate Methods === +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.worldData count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"UYLCountryCell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; + NSDictionary *country = [self.worldData objectAtIndex:indexPath.row]; + cell.textLabel.text = [country valueForKey:@"name"]; + return cell; +} + +#pragma mark - +#pragma mark === State Preservation === +#pragma mark - + +- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view +{ + NSString *identifier = nil; + if (indexPath && view) + { + NSDictionary *country = [self.worldData objectAtIndex:indexPath.row]; + identifier = [country valueForKey:@"name"]; + } + return identifier; +} + +- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view +{ + NSIndexPath *indexPath = nil; + if (identifier && view) + { + NSPredicate *namePred = [NSPredicate predicateWithFormat:@"name == %@", identifier]; + NSInteger row = [self.worldData indexOfObjectPassingTest: + ^(id obj, NSUInteger idx, BOOL *stop) + { + return [namePred evaluateWithObject:obj]; + }]; + + if (row != NSNotFound) + { + indexPath = [NSIndexPath indexPathForRow:row inSection:0]; + } + } + + // Force a reload when table view is embedded in nav controller + // or scroll position is not restored. Uncomment following line + // to workaround bug. + [self.tableView reloadData]; + + return indexPath; +} + + +@end diff --git a/Restorer/Restorer/UYLWebViewController.h b/Restorer/Restorer/UYLWebViewController.h new file mode 100644 index 0000000..8369e78 --- /dev/null +++ b/Restorer/Restorer/UYLWebViewController.h @@ -0,0 +1,38 @@ +// +// UYLWebViewController.h +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLWebViewController : UIViewController +@property (nonatomic, copy) NSString *urlString; +@end diff --git a/Restorer/Restorer/UYLWebViewController.m b/Restorer/Restorer/UYLWebViewController.m new file mode 100644 index 0000000..b4bef91 --- /dev/null +++ b/Restorer/Restorer/UYLWebViewController.m @@ -0,0 +1,96 @@ +// +// UYLWebViewController.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import +#import "UYLWebViewController.h" + +@interface UYLWebViewController () +@property (strong, nonatomic) IBOutlet WKWebView *webView; +@end + +@implementation UYLWebViewController + +static NSString *UYLKeyURL = @"UYLKeyURL"; + +#pragma mark - +#pragma mark === View Life Cycle Management === +#pragma mark - + +- (void)setUrlString:(NSString *)urlString { + if (_urlString != urlString) { + _urlString = [urlString copy]; + [self loadPage]; + } +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [self loadPage]; +} + +- (void)loadPage +{ + NSURL *URL = [NSURL URLWithString:self.urlString]; + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + [self.webView loadRequest:request]; +} + +#pragma mark - +#pragma mark === State Restoration === +#pragma mark - + +- (void)encodeRestorableStateWithCoder:(NSCoder *)coder +{ + [coder encodeObject:self.urlString forKey:UYLKeyURL]; + [super encodeRestorableStateWithCoder:coder]; +} + +- (void)decodeRestorableStateWithCoder:(NSCoder *)coder +{ + [super decodeRestorableStateWithCoder:coder]; + self.urlString = [coder decodeObjectForKey:UYLKeyURL]; +} + +#pragma mark - +#pragma mark === UIViewControllerRestoration Protocol === +#pragma mark - + ++ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder +{ + UIViewController *viewController = [[UYLWebViewController alloc] initWithNibName:@"UYLWebViewController" bundle:nil]; + viewController.restorationIdentifier = [identifierComponents lastObject]; + viewController.restorationClass = [UYLWebViewController class]; + return viewController; +} + +@end diff --git a/Restorer/Restorer/countries.plist b/Restorer/Restorer/countries.plist new file mode 100644 index 0000000..209a279 --- /dev/null +++ b/Restorer/Restorer/countries.plist @@ -0,0 +1,254 @@ +( +{name="Andorra";capital="Andorra la Vella";area="468";population=84000;continent="EU";tld=".ad";currency="Euro";phone="376";}, +{name="United Arab Emirates";capital="Abu Dhabi";area="82880";population=4975593;continent="AS";tld=".ae";currency="Dirham";phone="971";}, +{name="Afghanistan";capital="Kabul";area="647500";population=29121286;continent="AS";tld=".af";currency="Afghani";phone="93";}, +{name="Antigua and Barbuda";capital="St. John's";area="443";population=86754;continent="NA";tld=".ag";currency="Dollar";phone="+1-268";}, +{name="Anguilla";capital="The Valley";area="102";population=13254;continent="NA";tld=".ai";currency="Dollar";phone="+1-264";}, +{name="Albania";capital="Tirana";area="28748";population=2986952;continent="EU";tld=".al";currency="Lek";phone="355";}, +{name="Armenia";capital="Yerevan";area="29800";population=2968000;continent="AS";tld=".am";currency="Dram";phone="374";}, +{name="Angola";capital="Luanda";area="1246700";population=13068161;continent="AF";tld=".ao";currency="Kwanza";phone="244";}, +{name="Antarctica";capital="";area="1.40E+007";population=0;continent="AN";tld=".aq";currency="";phone="";}, +{name="Argentina";capital="Buenos Aires";area="2766890";population=41343201;continent="SA";tld=".ar";currency="Peso";phone="54";}, +{name="American Samoa";capital="Pago Pago";area="199";population=57881;continent="OC";tld=".as";currency="Dollar";phone="+1-684";}, +{name="Austria";capital="Vienna";area="83858";population=8205000;continent="EU";tld=".at";currency="Euro";phone="43";}, +{name="Australia";capital="Canberra";area="7686850";population=21515754;continent="OC";tld=".au";currency="Dollar";phone="61";}, +{name="Aruba";capital="Oranjestad";area="193";population=71566;continent="NA";tld=".aw";currency="Guilder";phone="297";}, +{name="Aland Islands";capital="Mariehamn";area="";population=26711;continent="EU";tld=".ax";currency="Euro";phone="+358-18";}, +{name="Azerbaijan";capital="Baku";area="86600";population=8303512;continent="AS";tld=".az";currency="Manat";phone="994";}, +{name="Bosnia and Herzegovina";capital="Sarajevo";area="51129";population=4590000;continent="EU";tld=".ba";currency="Marka";phone="387";}, +{name="Barbados";capital="Bridgetown";area="431";population=285653;continent="NA";tld=".bb";currency="Dollar";phone="+1-246";}, +{name="Bangladesh";capital="Dhaka";area="144000";population=156118464;continent="AS";tld=".bd";currency="Taka";phone="880";}, +{name="Belgium";capital="Brussels";area="30510";population=10403000;continent="EU";tld=".be";currency="Euro";phone="32";}, +{name="Burkina Faso";capital="Ouagadougou";area="274200";population=16241811;continent="AF";tld=".bf";currency="Franc";phone="226";}, +{name="Bulgaria";capital="Sofia";area="110910";population=7148785;continent="EU";tld=".bg";currency="Lev";phone="359";}, +{name="Bahrain";capital="Manama";area="665";population=738004;continent="AS";tld=".bh";currency="Dinar";phone="973";}, +{name="Burundi";capital="Bujumbura";area="27830";population=9863117;continent="AF";tld=".bi";currency="Franc";phone="257";}, +{name="Benin";capital="Porto-Novo";area="112620";population=9056010;continent="AF";tld=".bj";currency="Franc";phone="229";}, +{name="Saint Barthelemy";capital="Gustavia";area="21";population=8450;continent="NA";tld=".gp";currency="Euro";phone="590";}, +{name="Bermuda";capital="Hamilton";area="53";population=65365;continent="NA";tld=".bm";currency="Dollar";phone="+1-441";}, +{name="Brunei";capital="Bandar Seri Begawan";area="5770";population=395027;continent="AS";tld=".bn";currency="Dollar";phone="673";}, +{name="Bolivia";capital="Sucre";area="1098580";population=9947418;continent="SA";tld=".bo";currency="Boliviano";phone="591";}, +{name="Bonaire, Saint Eustatius and Saba ";capital="";area="";population=18012;continent="NA";tld=".bq";currency="Dollar";phone="599";}, +{name="Brazil";capital="Brasilia";area="8511965";population=201103330;continent="SA";tld=".br";currency="Real";phone="55";}, +{name="Bahamas";capital="Nassau";area="13940";population=301790;continent="NA";tld=".bs";currency="Dollar";phone="+1-242";}, +{name="Bhutan";capital="Thimphu";area="47000";population=699847;continent="AS";tld=".bt";currency="Ngultrum";phone="975";}, +{name="Bouvet Island";capital="";area="";population=0;continent="AN";tld=".bv";currency="Krone";phone="";}, +{name="Botswana";capital="Gaborone";area="600370";population=2029307;continent="AF";tld=".bw";currency="Pula";phone="267";}, +{name="Belarus";capital="Minsk";area="207600";population=9685000;continent="EU";tld=".by";currency="Ruble";phone="375";}, +{name="Belize";capital="Belmopan";area="22966";population=314522;continent="NA";tld=".bz";currency="Dollar";phone="501";}, +{name="Canada";capital="Ottawa";area="9984670";population=33679000;continent="NA";tld=".ca";currency="Dollar";phone="1";}, +{name="Cocos Islands";capital="West Island";area="14";population=628;continent="AS";tld=".cc";currency="Dollar";phone="61";}, +{name="Democratic Republic of the Congo";capital="Kinshasa";area="2345410";population=70916439;continent="AF";tld=".cd";currency="Franc";phone="243";}, +{name="Central African Republic";capital="Bangui";area="622984";population=4844927;continent="AF";tld=".cf";currency="Franc";phone="236";}, +{name="Republic of the Congo";capital="Brazzaville";area="342000";population=3039126;continent="AF";tld=".cg";currency="Franc";phone="242";}, +{name="Switzerland";capital="Berne";area="41290";population=7581000;continent="EU";tld=".ch";currency="Franc";phone="41";}, +{name="Ivory Coast";capital="Yamoussoukro";area="322460";population=21058798;continent="AF";tld=".ci";currency="Franc";phone="225";}, +{name="Cook Islands";capital="Avarua";area="240";population=21388;continent="OC";tld=".ck";currency="Dollar";phone="682";}, +{name="Chile";capital="Santiago";area="756950";population=16746491;continent="SA";tld=".cl";currency="Peso";phone="56";}, +{name="Cameroon";capital="Yaounde";area="475440";population=19294149;continent="AF";tld=".cm";currency="Franc";phone="237";}, +{name="China";capital="Beijing";area="9596960";population=1330044000;continent="AS";tld=".cn";currency="Yuan Renminbi";phone="86";}, +{name="Colombia";capital="Bogota";area="1138910";population=44205293;continent="SA";tld=".co";currency="Peso";phone="57";}, +{name="Costa Rica";capital="San Jose";area="51100";population=4516220;continent="NA";tld=".cr";currency="Colon";phone="506";}, +{name="Cuba";capital="Havana";area="110860";population=11423000;continent="NA";tld=".cu";currency="Peso";phone="53";}, +{name="Cape Verde";capital="Praia";area="4033";population=508659;continent="AF";tld=".cv";currency="Escudo";phone="238";}, +{name="Curacao";capital=" Willemstad";area="";population=141766;continent="NA";tld=".cw";currency="Guilder";phone="599";}, +{name="Christmas Island";capital="Flying Fish Cove";area="135";population=1500;continent="AS";tld=".cx";currency="Dollar";phone="61";}, +{name="Cyprus";capital="Nicosia";area="9250";population=1102677;continent="EU";tld=".cy";currency="Euro";phone="357";}, +{name="Czech Republic";capital="Prague";area="78866";population=10476000;continent="EU";tld=".cz";currency="Koruna";phone="420";}, +{name="Germany";capital="Berlin";area="357021";population=81802257;continent="EU";tld=".de";currency="Euro";phone="49";}, +{name="Djibouti";capital="Djibouti";area="23000";population=740528;continent="AF";tld=".dj";currency="Franc";phone="253";}, +{name="Denmark";capital="Copenhagen";area="43094";population=5484000;continent="EU";tld=".dk";currency="Krone";phone="45";}, +{name="Dominica";capital="Roseau";area="754";population=72813;continent="NA";tld=".dm";currency="Dollar";phone="+1-767";}, +{name="Dominican Republic";capital="Santo Domingo";area="48730";population=9823821;continent="NA";tld=".do";currency="Peso";phone="+1-809 and 1-829";}, +{name="Algeria";capital="Algiers";area="2381740";population=34586184;continent="AF";tld=".dz";currency="Dinar";phone="213";}, +{name="Ecuador";capital="Quito";area="283560";population=14790608;continent="SA";tld=".ec";currency="Dollar";phone="593";}, +{name="Estonia";capital="Tallinn";area="45226";population=1291170;continent="EU";tld=".ee";currency="Euro";phone="372";}, +{name="Egypt";capital="Cairo";area="1001450";population=80471869;continent="AF";tld=".eg";currency="Pound";phone="20";}, +{name="Western Sahara";capital="El-Aaiun";area="266000";population=273008;continent="AF";tld=".eh";currency="Dirham";phone="212";}, +{name="Eritrea";capital="Asmara";area="121320";population=5792984;continent="AF";tld=".er";currency="Nakfa";phone="291";}, +{name="Spain";capital="Madrid";area="504782";population=46505963;continent="EU";tld=".es";currency="Euro";phone="34";}, +{name="Ethiopia";capital="Addis Ababa";area="1127127";population=88013491;continent="AF";tld=".et";currency="Birr";phone="251";}, +{name="Finland";capital="Helsinki";area="337030";population=5244000;continent="EU";tld=".fi";currency="Euro";phone="358";}, +{name="Fiji";capital="Suva";area="18270";population=875983;continent="OC";tld=".fj";currency="Dollar";phone="679";}, +{name="Falkland Islands";capital="Stanley";area="12173";population=2638;continent="SA";tld=".fk";currency="Pound";phone="500";}, +{name="Micronesia";capital="Palikir";area="702";population=107708;continent="OC";tld=".fm";currency="Dollar";phone="691";}, +{name="Faroe Islands";capital="Torshavn";area="1399";population=48228;continent="EU";tld=".fo";currency="Krone";phone="298";}, +{name="France";capital="Paris";area="547030";population=64768389;continent="EU";tld=".fr";currency="Euro";phone="33";}, +{name="Gabon";capital="Libreville";area="267667";population=1545255;continent="AF";tld=".ga";currency="Franc";phone="241";}, +{name="United Kingdom";capital="London";area="244820";population=62348447;continent="EU";tld=".uk";currency="Pound";phone="44";}, +{name="Grenada";capital="St. George's";area="344";population=107818;continent="NA";tld=".gd";currency="Dollar";phone="+1-473";}, +{name="Georgia";capital="Tbilisi";area="69700";population=4630000;continent="AS";tld=".ge";currency="Lari";phone="995";}, +{name="French Guiana";capital="Cayenne";area="91000";population=195506;continent="SA";tld=".gf";currency="Euro";phone="594";}, +{name="Guernsey";capital="St Peter Port";area="78";population=65228;continent="EU";tld=".gg";currency="Pound";phone="+44-1481";}, +{name="Ghana";capital="Accra";area="239460";population=24339838;continent="AF";tld=".gh";currency="Cedi";phone="233";}, +{name="Gibraltar";capital="Gibraltar";area="6.5";population=27884;continent="EU";tld=".gi";currency="Pound";phone="350";}, +{name="Greenland";capital="Nuuk";area="2166086";population=56375;continent="NA";tld=".gl";currency="Krone";phone="299";}, +{name="Gambia";capital="Banjul";area="11300";population=1593256;continent="AF";tld=".gm";currency="Dalasi";phone="220";}, +{name="Guinea";capital="Conakry";area="245857";population=10324025;continent="AF";tld=".gn";currency="Franc";phone="224";}, +{name="Guadeloupe";capital="Basse-Terre";area="1780";population=443000;continent="NA";tld=".gp";currency="Euro";phone="590";}, +{name="Equatorial Guinea";capital="Malabo";area="28051";population=1014999;continent="AF";tld=".gq";currency="Franc";phone="240";}, +{name="Greece";capital="Athens";area="131940";population=11000000;continent="EU";tld=".gr";currency="Euro";phone="30";}, +{name="South Georgia and the South Sandwich Islands";capital="Grytviken";area="3903";population=30;continent="AN";tld=".gs";currency="Pound";phone="";}, +{name="Guatemala";capital="Guatemala City";area="108890";population=13550440;continent="NA";tld=".gt";currency="Quetzal";phone="502";}, +{name="Guam";capital="Hagatna";area="549";population=159358;continent="OC";tld=".gu";currency="Dollar";phone="+1-671";}, +{name="Guinea-Bissau";capital="Bissau";area="36120";population=1565126;continent="AF";tld=".gw";currency="Franc";phone="245";}, +{name="Guyana";capital="Georgetown";area="214970";population=748486;continent="SA";tld=".gy";currency="Dollar";phone="592";}, +{name="Hong Kong";capital="Hong Kong";area="1092";population=6898686;continent="AS";tld=".hk";currency="Dollar";phone="852";}, +{name="Heard Island and McDonald Islands";capital="";area="412";population=0;continent="AN";tld=".hm";currency="Dollar";phone=" ";}, +{name="Honduras";capital="Tegucigalpa";area="112090";population=7989415;continent="NA";tld=".hn";currency="Lempira";phone="504";}, +{name="Croatia";capital="Zagreb";area="56542";population=4491000;continent="EU";tld=".hr";currency="Kuna";phone="385";}, +{name="Haiti";capital="Port-au-Prince";area="27750";population=9648924;continent="NA";tld=".ht";currency="Gourde";phone="509";}, +{name="Hungary";capital="Budapest";area="93030";population=9930000;continent="EU";tld=".hu";currency="Forint";phone="36";}, +{name="Indonesia";capital="Jakarta";area="1919440";population=242968342;continent="AS";tld=".id";currency="Rupiah";phone="62";}, +{name="Ireland";capital="Dublin";area="70280";population=4622917;continent="EU";tld=".ie";currency="Euro";phone="353";}, +{name="Israel";capital="Jerusalem";area="20770";population=7353985;continent="AS";tld=".il";currency="Shekel";phone="972";}, +{name="Isle of Man";capital="Douglas, Isle of Man";area="572";population=75049;continent="EU";tld=".im";currency="Pound";phone="+44-1624";}, +{name="India";capital="New Delhi";area="3287590";population=1173108018;continent="AS";tld=".in";currency="Rupee";phone="91";}, +{name="British Indian Ocean Territory";capital="Diego Garcia";area="60";population=4000;continent="AS";tld=".io";currency="Dollar";phone="246";}, +{name="Iraq";capital="Baghdad";area="437072";population=29671605;continent="AS";tld=".iq";currency="Dinar";phone="964";}, +{name="Iran";capital="Tehran";area="1648000";population=76923300;continent="AS";tld=".ir";currency="Rial";phone="98";}, +{name="Iceland";capital="Reykjavik";area="103000";population=308910;continent="EU";tld=".is";currency="Krona";phone="354";}, +{name="Italy";capital="Rome";area="301230";population=60340328;continent="EU";tld=".it";currency="Euro";phone="39";}, +{name="Jersey";capital="Saint Helier";area="116";population=90812;continent="EU";tld=".je";currency="Pound";phone="+44-1534";}, +{name="Jamaica";capital="Kingston";area="10991";population=2847232;continent="NA";tld=".jm";currency="Dollar";phone="+1-876";}, +{name="Jordan";capital="Amman";area="92300";population=6407085;continent="AS";tld=".jo";currency="Dinar";phone="962";}, +{name="Japan";capital="Tokyo";area="377835";population=127288000;continent="AS";tld=".jp";currency="Yen";phone="81";}, +{name="Kenya";capital="Nairobi";area="582650";population=40046566;continent="AF";tld=".ke";currency="Shilling";phone="254";}, +{name="Kyrgyzstan";capital="Bishkek";area="198500";population=5508626;continent="AS";tld=".kg";currency="Som";phone="996";}, +{name="Cambodia";capital="Phnom Penh";area="181040";population=14453680;continent="AS";tld=".kh";currency="Riels";phone="855";}, +{name="Kiribati";capital="Tarawa";area="811";population=92533;continent="OC";tld=".ki";currency="Dollar";phone="686";}, +{name="Comoros";capital="Moroni";area="2170";population=773407;continent="AF";tld=".km";currency="Franc";phone="269";}, +{name="Saint Kitts and Nevis";capital="Basseterre";area="261";population=49898;continent="NA";tld=".kn";currency="Dollar";phone="+1-869";}, +{name="North Korea";capital="Pyongyang";area="120540";population=22912177;continent="AS";tld=".kp";currency="Won";phone="850";}, +{name="South Korea";capital="Seoul";area="98480";population=48422644;continent="AS";tld=".kr";currency="Won";phone="82";}, +{name="Kosovo";capital="Pristina";area="";population=1800000;continent="EU";tld="";currency="Euro";phone="";}, +{name="Kuwait";capital="Kuwait City";area="17820";population=2789132;continent="AS";tld=".kw";currency="Dinar";phone="965";}, +{name="Cayman Islands";capital="George Town";area="262";population=44270;continent="NA";tld=".ky";currency="Dollar";phone="+1-345";}, +{name="Kazakhstan";capital="Astana";area="2717300";population=15340000;continent="AS";tld=".kz";currency="Tenge";phone="7";}, +{name="Laos";capital="Vientiane";area="236800";population=6368162;continent="AS";tld=".la";currency="Kip";phone="856";}, +{name="Lebanon";capital="Beirut";area="10400";population=4125247;continent="AS";tld=".lb";currency="Pound";phone="961";}, +{name="Saint Lucia";capital="Castries";area="616";population=160922;continent="NA";tld=".lc";currency="Dollar";phone="+1-758";}, +{name="Liechtenstein";capital="Vaduz";area="160";population=35000;continent="EU";tld=".li";currency="Franc";phone="423";}, +{name="Sri Lanka";capital="Colombo";area="65610";population=21513990;continent="AS";tld=".lk";currency="Rupee";phone="94";}, +{name="Liberia";capital="Monrovia";area="111370";population=3685076;continent="AF";tld=".lr";currency="Dollar";phone="231";}, +{name="Lesotho";capital="Maseru";area="30355";population=1919552;continent="AF";tld=".ls";currency="Loti";phone="266";}, +{name="Lithuania";capital="Vilnius";area="65200";population=3565000;continent="EU";tld=".lt";currency="Litas";phone="370";}, +{name="Luxembourg";capital="Luxembourg";area="2586";population=497538;continent="EU";tld=".lu";currency="Euro";phone="352";}, +{name="Latvia";capital="Riga";area="64589";population=2217969;continent="EU";tld=".lv";currency="Lat";phone="371";}, +{name="Libya";capital="Tripolis";area="1759540";population=6461454;continent="AF";tld=".ly";currency="Dinar";phone="218";}, +{name="Morocco";capital="Rabat";area="446550";population=31627428;continent="AF";tld=".ma";currency="Dirham";phone="212";}, +{name="Monaco";capital="Monaco";area="1.95";population=32965;continent="EU";tld=".mc";currency="Euro";phone="377";}, +{name="Moldova";capital="Chisinau";area="33843";population=4324000;continent="EU";tld=".md";currency="Leu";phone="373";}, +{name="Montenegro";capital="Podgorica";area="14026";population=666730;continent="EU";tld=".me";currency="Euro";phone="382";}, +{name="Saint Martin";capital="Marigot";area="53";population=35925;continent="NA";tld=".gp";currency="Euro";phone="590";}, +{name="Madagascar";capital="Antananarivo";area="587040";population=21281844;continent="AF";tld=".mg";currency="Ariary";phone="261";}, +{name="Marshall Islands";capital="Majuro";area="181.3";population=65859;continent="OC";tld=".mh";currency="Dollar";phone="692";}, +{name="Macedonia";capital="Skopje";area="25333";population=2061000;continent="EU";tld=".mk";currency="Denar";phone="389";}, +{name="Mali";capital="Bamako";area="1240000";population=13796354;continent="AF";tld=".ml";currency="Franc";phone="223";}, +{name="Myanmar";capital="Nay Pyi Taw";area="678500";population=53414374;continent="AS";tld=".mm";currency="Kyat";phone="95";}, +{name="Mongolia";capital="Ulan Bator";area="1565000";population=3086918;continent="AS";tld=".mn";currency="Tugrik";phone="976";}, +{name="Macao";capital="Macao";area="254";population=449198;continent="AS";tld=".mo";currency="Pataca";phone="853";}, +{name="Northern Mariana Islands";capital="Saipan";area="477";population=53883;continent="OC";tld=".mp";currency="Dollar";phone="+1-670";}, +{name="Martinique";capital="Fort-de-France";area="1100";population=432900;continent="NA";tld=".mq";currency="Euro";phone="596";}, +{name="Mauritania";capital="Nouakchott";area="1030700";population=3205060;continent="AF";tld=".mr";currency="Ouguiya";phone="222";}, +{name="Montserrat";capital="Plymouth";area="102";population=9341;continent="NA";tld=".ms";currency="Dollar";phone="+1-664";}, +{name="Malta";capital="Valletta";area="316";population=403000;continent="EU";tld=".mt";currency="Euro";phone="356";}, +{name="Mauritius";capital="Port Louis";area="2040";population=1294104;continent="AF";tld=".mu";currency="Rupee";phone="230";}, +{name="Maldives";capital="Male";area="300";population=395650;continent="AS";tld=".mv";currency="Rufiyaa";phone="960";}, +{name="Malawi";capital="Lilongwe";area="118480";population=15447500;continent="AF";tld=".mw";currency="Kwacha";phone="265";}, +{name="Mexico";capital="Mexico City";area="1972550";population=112468855;continent="NA";tld=".mx";currency="Peso";phone="52";}, +{name="Malaysia";capital="Kuala Lumpur";area="329750";population=28274729;continent="AS";tld=".my";currency="Ringgit";phone="60";}, +{name="Mozambique";capital="Maputo";area="801590";population=22061451;continent="AF";tld=".mz";currency="Metical";phone="258";}, +{name="Namibia";capital="Windhoek";area="825418";population=2128471;continent="AF";tld=".na";currency="Dollar";phone="264";}, +{name="New Caledonia";capital="Noumea";area="19060";population=216494;continent="OC";tld=".nc";currency="Franc";phone="687";}, +{name="Niger";capital="Niamey";area="1267000";population=15878271;continent="AF";tld=".ne";currency="Franc";phone="227";}, +{name="Norfolk Island";capital="Kingston";area="34.6";population=1828;continent="OC";tld=".nf";currency="Dollar";phone="672";}, +{name="Nigeria";capital="Abuja";area="923768";population=154000000;continent="AF";tld=".ng";currency="Naira";phone="234";}, +{name="Nicaragua";capital="Managua";area="129494";population=5995928;continent="NA";tld=".ni";currency="Cordoba";phone="505";}, +{name="Netherlands";capital="Amsterdam";area="41526";population=16645000;continent="EU";tld=".nl";currency="Euro";phone="31";}, +{name="Norway";capital="Oslo";area="324220";population=4985870;continent="EU";tld=".no";currency="Krone";phone="47";}, +{name="Nepal";capital="Kathmandu";area="140800";population=28951852;continent="AS";tld=".np";currency="Rupee";phone="977";}, +{name="Nauru";capital="Yaren";area="21";population=10065;continent="OC";tld=".nr";currency="Dollar";phone="674";}, +{name="Niue";capital="Alofi";area="260";population=2166;continent="OC";tld=".nu";currency="Dollar";phone="683";}, +{name="New Zealand";capital="Wellington";area="268680";population=4252277;continent="OC";tld=".nz";currency="Dollar";phone="64";}, +{name="Oman";capital="Muscat";area="212460";population=2967717;continent="AS";tld=".om";currency="Rial";phone="968";}, +{name="Panama";capital="Panama City";area="78200";population=3410676;continent="NA";tld=".pa";currency="Balboa";phone="507";}, +{name="Peru";capital="Lima";area="1285220";population=29907003;continent="SA";tld=".pe";currency="Sol";phone="51";}, +{name="French Polynesia";capital="Papeete";area="4167";population=270485;continent="OC";tld=".pf";currency="Franc";phone="689";}, +{name="Papua New Guinea";capital="Port Moresby";area="462840";population=6064515;continent="OC";tld=".pg";currency="Kina";phone="675";}, +{name="Philippines";capital="Manila";area="300000";population=99900177;continent="AS";tld=".ph";currency="Peso";phone="63";}, +{name="Pakistan";capital="Islamabad";area="803940";population=184404791;continent="AS";tld=".pk";currency="Rupee";phone="92";}, +{name="Poland";capital="Warsaw";area="312685";population=38500000;continent="EU";tld=".pl";currency="Zloty";phone="48";}, +{name="Saint Pierre and Miquelon";capital="Saint-Pierre";area="242";population=7012;continent="NA";tld=".pm";currency="Euro";phone="508";}, +{name="Pitcairn";capital="Adamstown";area="47";population=46;continent="OC";tld=".pn";currency="Dollar";phone="870";}, +{name="Puerto Rico";capital="San Juan";area="9104";population=3916632;continent="NA";tld=".pr";currency="Dollar";phone="+1-787 and 1-939";}, +{name="Palestinian Territory";capital="East Jerusalem";area="5970";population=3800000;continent="AS";tld=".ps";currency="Shekel";phone="970";}, +{name="Portugal";capital="Lisbon";area="92391";population=10676000;continent="EU";tld=".pt";currency="Euro";phone="351";}, +{name="Palau";capital="Melekeok";area="458";population=19907;continent="OC";tld=".pw";currency="Dollar";phone="680";}, +{name="Paraguay";capital="Asuncion";area="406750";population=6375830;continent="SA";tld=".py";currency="Guarani";phone="595";}, +{name="Qatar";capital="Doha";area="11437";population=840926;continent="AS";tld=".qa";currency="Rial";phone="974";}, +{name="Reunion";capital="Saint-Denis";area="2517";population=776948;continent="AF";tld=".re";currency="Euro";phone="262";}, +{name="Romania";capital="Bucharest";area="237500";population=21959278;continent="EU";tld=".ro";currency="Leu";phone="40";}, +{name="Serbia";capital="Belgrade";area="88361";population=7344847;continent="EU";tld=".rs";currency="Dinar";phone="381";}, +{name="Russia";capital="Moscow";area="1.71E+007";population=140702000;continent="EU";tld=".ru";currency="Ruble";phone="7";}, +{name="Rwanda";capital="Kigali";area="26338";population=11055976;continent="AF";tld=".rw";currency="Franc";phone="250";}, +{name="Saudi Arabia";capital="Riyadh";area="1960582";population=25731776;continent="AS";tld=".sa";currency="Rial";phone="966";}, +{name="Solomon Islands";capital="Honiara";area="28450";population=559198;continent="OC";tld=".sb";currency="Dollar";phone="677";}, +{name="Seychelles";capital="Victoria";area="455";population=88340;continent="AF";tld=".sc";currency="Rupee";phone="248";}, +{name="Sudan";capital="Khartoum";area="1861484";population=35000000;continent="AF";tld=".sd";currency="Pound";phone="249";}, +{name="South Sudan";capital="Juba";area="644329";population=8260490;continent="AF";tld="";currency="Pound";phone="211";}, +{name="Sweden";capital="Stockholm";area="449964";population=9045000;continent="EU";tld=".se";currency="Krona";phone="46";}, +{name="Singapore";capital="Singapur";area="692.7";population=4701069;continent="AS";tld=".sg";currency="Dollar";phone="65";}, +{name="Saint Helena";capital="Jamestown";area="410";population=7460;continent="AF";tld=".sh";currency="Pound";phone="290";}, +{name="Slovenia";capital="Ljubljana";area="20273";population=2007000;continent="EU";tld=".si";currency="Euro";phone="386";}, +{name="Svalbard and Jan Mayen";capital="Longyearbyen";area="62049";population=2550;continent="EU";tld=".sj";currency="Krone";phone="47";}, +{name="Slovakia";capital="Bratislava";area="48845";population=5455000;continent="EU";tld=".sk";currency="Euro";phone="421";}, +{name="Sierra Leone";capital="Freetown";area="71740";population=5245695;continent="AF";tld=".sl";currency="Leone";phone="232";}, +{name="San Marino";capital="San Marino";area="61.2";population=31477;continent="EU";tld=".sm";currency="Euro";phone="378";}, +{name="Senegal";capital="Dakar";area="196190";population=12323252;continent="AF";tld=".sn";currency="Franc";phone="221";}, +{name="Somalia";capital="Mogadishu";area="637657";population=10112453;continent="AF";tld=".so";currency="Shilling";phone="252";}, +{name="Suriname";capital="Paramaribo";area="163270";population=492829;continent="SA";tld=".sr";currency="Dollar";phone="597";}, +{name="Sao Tome and Principe";capital="Sao Tome";area="1001";population=175808;continent="AF";tld=".st";currency="Dobra";phone="239";}, +{name="El Salvador";capital="San Salvador";area="21040";population=6052064;continent="NA";tld=".sv";currency="Dollar";phone="503";}, +{name="Sint Maarten";capital="Philipsburg";area="";population=37429;continent="NA";tld=".sx";currency="Guilder";phone="599";}, +{name="Syria";capital="Damascus";area="185180";population=22198110;continent="AS";tld=".sy";currency="Pound";phone="963";}, +{name="Swaziland";capital="Mbabane";area="17363";population=1354051;continent="AF";tld=".sz";currency="Lilangeni";phone="268";}, +{name="Turks and Caicos Islands";capital="Cockburn Town";area="430";population=20556;continent="NA";tld=".tc";currency="Dollar";phone="+1-649";}, +{name="Chad";capital="N'Djamena";area="1284000";population=10543464;continent="AF";tld=".td";currency="Franc";phone="235";}, +{name="French Southern Territories";capital="Port-aux-Francais";area="7829";population=140;continent="AN";tld=".tf";currency="Euro ";phone="";}, +{name="Togo";capital="Lome";area="56785";population=6587239;continent="AF";tld=".tg";currency="Franc";phone="228";}, +{name="Thailand";capital="Bangkok";area="514000";population=67089500;continent="AS";tld=".th";currency="Baht";phone="66";}, +{name="Tajikistan";capital="Dushanbe";area="143100";population=7487489;continent="AS";tld=".tj";currency="Somoni";phone="992";}, +{name="Tokelau";capital="";area="10";population=1466;continent="OC";tld=".tk";currency="Dollar";phone="690";}, +{name="East Timor";capital="Dili";area="15007";population=1154625;continent="OC";tld=".tl";currency="Dollar";phone="670";}, +{name="Turkmenistan";capital="Ashgabat";area="488100";population=4940916;continent="AS";tld=".tm";currency="Manat";phone="993";}, +{name="Tunisia";capital="Tunis";area="163610";population=10589025;continent="AF";tld=".tn";currency="Dinar";phone="216";}, +{name="Tonga";capital="Nuku'alofa";area="748";population=122580;continent="OC";tld=".to";currency="Pa'anga";phone="676";}, +{name="Turkey";capital="Ankara";area="780580";population=77804122;continent="AS";tld=".tr";currency="Lira";phone="90";}, +{name="Trinidad and Tobago";capital="Port of Spain";area="5128";population=1228691;continent="NA";tld=".tt";currency="Dollar";phone="+1-868";}, +{name="Tuvalu";capital="Funafuti";area="26";population=10472;continent="OC";tld=".tv";currency="Dollar";phone="688";}, +{name="Taiwan";capital="Taipei";area="35980";population=22894384;continent="AS";tld=".tw";currency="Dollar";phone="886";}, +{name="Tanzania";capital="Dodoma";area="945087";population=41892895;continent="AF";tld=".tz";currency="Shilling";phone="255";}, +{name="Ukraine";capital="Kiev";area="603700";population=45415596;continent="EU";tld=".ua";currency="Hryvnia";phone="380";}, +{name="Uganda";capital="Kampala";area="236040";population=33398682;continent="AF";tld=".ug";currency="Shilling";phone="256";}, +{name="United States Minor Outlying Islands";capital="";area="0";population=0;continent="OC";tld=".um";currency="Dollar ";phone="1";}, +{name="United States";capital="Washington";area="9629091";population=310232863;continent="NA";tld=".us";currency="Dollar";phone="1";}, +{name="Uruguay";capital="Montevideo";area="176220";population=3477000;continent="SA";tld=".uy";currency="Peso";phone="598";}, +{name="Uzbekistan";capital="Tashkent";area="447400";population=27865738;continent="AS";tld=".uz";currency="Som";phone="998";}, +{name="Vatican";capital="Vatican City";area="0.44";population=921;continent="EU";tld=".va";currency="Euro";phone="379";}, +{name="Saint Vincent and the Grenadines";capital="Kingstown";area="389";population=104217;continent="NA";tld=".vc";currency="Dollar";phone="+1-784";}, +{name="Venezuela";capital="Caracas";area="912050";population=27223228;continent="SA";tld=".ve";currency="Bolivar";phone="58";}, +{name="British Virgin Islands";capital="Road Town";area="153";population=21730;continent="NA";tld=".vg";currency="Dollar";phone="+1-284";}, +{name="U.S. Virgin Islands";capital="Charlotte Amalie";area="352";population=108708;continent="NA";tld=".vi";currency="Dollar";phone="+1-340";}, +{name="Vietnam";capital="Hanoi";area="329560";population=89571130;continent="AS";tld=".vn";currency="Dong";phone="84";}, +{name="Vanuatu";capital="Port Vila";area="12200";population=221552;continent="OC";tld=".vu";currency="Vatu";phone="678";}, +{name="Wallis and Futuna";capital="Mata Utu";area="274";population=16025;continent="OC";tld=".wf";currency="Franc";phone="681";}, +{name="Samoa";capital="Apia";area="2944";population=192001;continent="OC";tld=".ws";currency="Tala";phone="685";}, +{name="Yemen";capital="Sanaa";area="527970";population=23495361;continent="AS";tld=".ye";currency="Rial";phone="967";}, +{name="Mayotte";capital="Mamoudzou";area="374";population=159042;continent="AF";tld=".yt";currency="Euro";phone="262";}, +{name="South Africa";capital="Pretoria";area="1219912";population=49000000;continent="AF";tld=".za";currency="Rand";phone="27";}, +{name="Zambia";capital="Lusaka";area="752614";population=13460305;continent="AF";tld=".zm";currency="Kwacha";phone="260";}, +{name="Zimbabwe";capital="Harare";area="390580";population=11651858;continent="AF";tld=".zw";currency="Dollar";phone="263";}, +{name="Serbia and Montenegro";capital="Belgrade";area="102350";population=10829175;continent="EU";tld=".cs";currency="Dinar";phone="381";}, +{name="Netherlands Antilles";capital="Willemstad";area="960";population=136197;continent="NA";tld=".an";currency="Guilder";phone="599";} +) diff --git a/Restorer/Restorer/en.lproj/InfoPlist.strings b/Restorer/Restorer/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Restorer/Restorer/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Restorer/Restorer/main.m b/Restorer/Restorer/main.m new file mode 100644 index 0000000..20c716c --- /dev/null +++ b/Restorer/Restorer/main.m @@ -0,0 +1,43 @@ +// +// main.m +// Restorer +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2013 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/RevealStack/README.md b/RevealStack/README.md new file mode 100644 index 0000000..8e4c4af --- /dev/null +++ b/RevealStack/README.md @@ -0,0 +1,13 @@ +### RevealStack - Background Views for Stack Views + +An example of adding subviews to a stack view without adding them to +`arrangedSubviews`. This is useful when you want the stack view to have +a background view or to add an overlay. + +See the following post for more: + ++ [Stack View Background Color](https://useyourloaf.com/blog/stack-view-background-color/) + +### Version History + ++ Version 1.0 03-Apr-2017 Initial Version diff --git a/RevealStack/RevealStack.xcodeproj/project.pbxproj b/RevealStack/RevealStack.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ee2d5f6 --- /dev/null +++ b/RevealStack/RevealStack.xcodeproj/project.pbxproj @@ -0,0 +1,338 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 535B225D1E915D1C002F6D4C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535B225C1E915D1C002F6D4C /* AppDelegate.swift */; }; + 535B22621E915D1C002F6D4C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 535B22601E915D1C002F6D4C /* Main.storyboard */; }; + 535B22641E915D1C002F6D4C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 535B22631E915D1C002F6D4C /* Assets.xcassets */; }; + 535B22671E915D1C002F6D4C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 535B22651E915D1C002F6D4C /* LaunchScreen.storyboard */; }; + 535B226F1E915D7B002F6D4C /* RevealViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535B226E1E915D7B002F6D4C /* RevealViewController.swift */; }; + 535B22711E915DA7002F6D4C /* UIView+UYLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535B22701E915DA7002F6D4C /* UIView+UYLExtensions.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 535B22591E915D1C002F6D4C /* RevealStack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RevealStack.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 535B225C1E915D1C002F6D4C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 535B22611E915D1C002F6D4C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 535B22631E915D1C002F6D4C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 535B22661E915D1C002F6D4C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 535B22681E915D1C002F6D4C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 535B226E1E915D7B002F6D4C /* RevealViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RevealViewController.swift; sourceTree = ""; }; + 535B22701E915DA7002F6D4C /* UIView+UYLExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+UYLExtensions.swift"; sourceTree = ""; }; + 535B22721E923F62002F6D4C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 535B22561E915D1C002F6D4C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 535B22501E915D1C002F6D4C = { + isa = PBXGroup; + children = ( + 535B22721E923F62002F6D4C /* README.md */, + 535B225B1E915D1C002F6D4C /* RevealStack */, + 535B225A1E915D1C002F6D4C /* Products */, + ); + sourceTree = ""; + }; + 535B225A1E915D1C002F6D4C /* Products */ = { + isa = PBXGroup; + children = ( + 535B22591E915D1C002F6D4C /* RevealStack.app */, + ); + name = Products; + sourceTree = ""; + }; + 535B225B1E915D1C002F6D4C /* RevealStack */ = { + isa = PBXGroup; + children = ( + 535B226E1E915D7B002F6D4C /* RevealViewController.swift */, + 535B225C1E915D1C002F6D4C /* AppDelegate.swift */, + 535B22701E915DA7002F6D4C /* UIView+UYLExtensions.swift */, + 535B22601E915D1C002F6D4C /* Main.storyboard */, + 535B22631E915D1C002F6D4C /* Assets.xcassets */, + 535B22651E915D1C002F6D4C /* LaunchScreen.storyboard */, + 535B22681E915D1C002F6D4C /* Info.plist */, + ); + path = RevealStack; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 535B22581E915D1C002F6D4C /* RevealStack */ = { + isa = PBXNativeTarget; + buildConfigurationList = 535B226B1E915D1C002F6D4C /* Build configuration list for PBXNativeTarget "RevealStack" */; + buildPhases = ( + 535B22551E915D1C002F6D4C /* Sources */, + 535B22561E915D1C002F6D4C /* Frameworks */, + 535B22571E915D1C002F6D4C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RevealStack; + productName = RevealStack; + productReference = 535B22591E915D1C002F6D4C /* RevealStack.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 535B22511E915D1C002F6D4C /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 535B22581E915D1C002F6D4C = { + CreatedOnToolsVersion = 8.3; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 535B22541E915D1C002F6D4C /* Build configuration list for PBXProject "RevealStack" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 535B22501E915D1C002F6D4C; + productRefGroup = 535B225A1E915D1C002F6D4C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 535B22581E915D1C002F6D4C /* RevealStack */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 535B22571E915D1C002F6D4C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 535B22671E915D1C002F6D4C /* LaunchScreen.storyboard in Resources */, + 535B22641E915D1C002F6D4C /* Assets.xcassets in Resources */, + 535B22621E915D1C002F6D4C /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 535B22551E915D1C002F6D4C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 535B225D1E915D1C002F6D4C /* AppDelegate.swift in Sources */, + 535B226F1E915D7B002F6D4C /* RevealViewController.swift in Sources */, + 535B22711E915DA7002F6D4C /* UIView+UYLExtensions.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 535B22601E915D1C002F6D4C /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 535B22611E915D1C002F6D4C /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 535B22651E915D1C002F6D4C /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 535B22661E915D1C002F6D4C /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 535B22691E915D1C002F6D4C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 535B226A1E915D1C002F6D4C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 535B226C1E915D1C002F6D4C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RevealStack/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RevealStack; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 535B226D1E915D1C002F6D4C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = RevealStack/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.RevealStack; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 535B22541E915D1C002F6D4C /* Build configuration list for PBXProject "RevealStack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 535B22691E915D1C002F6D4C /* Debug */, + 535B226A1E915D1C002F6D4C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 535B226B1E915D1C002F6D4C /* Build configuration list for PBXNativeTarget "RevealStack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 535B226C1E915D1C002F6D4C /* Debug */, + 535B226D1E915D1C002F6D4C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 535B22511E915D1C002F6D4C /* Project object */; +} diff --git a/RevealStack/RevealStack/AppDelegate.swift b/RevealStack/RevealStack/AppDelegate.swift new file mode 100644 index 0000000..62ee578 --- /dev/null +++ b/RevealStack/RevealStack/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// RevealStack +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/RevealStack/RevealStack/Assets.xcassets/AppIcon.appiconset/Contents.json b/RevealStack/RevealStack/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/RevealStack/RevealStack/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RevealStack/RevealStack/Assets.xcassets/Contents.json b/RevealStack/RevealStack/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/RevealStack/RevealStack/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/Contents.json b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/Contents.json new file mode 100644 index 0000000..581c8f1 --- /dev/null +++ b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "heart100.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "heart200.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "heart300.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart100.png b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart100.png new file mode 100644 index 0000000..d6be769 Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart100.png differ diff --git a/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart200.png b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart200.png new file mode 100644 index 0000000..932019f Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart200.png differ diff --git a/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart300.png b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart300.png new file mode 100644 index 0000000..c24ae62 Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Heart.imageset/heart300.png differ diff --git a/RevealStack/RevealStack/Assets.xcassets/Star.imageset/Contents.json b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/Contents.json new file mode 100644 index 0000000..9ee1843 --- /dev/null +++ b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star100.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "star200.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "star300.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star100.png b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star100.png new file mode 100644 index 0000000..4965255 Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star100.png differ diff --git a/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star200.png b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star200.png new file mode 100644 index 0000000..49311bc Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star200.png differ diff --git a/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star300.png b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star300.png new file mode 100644 index 0000000..d46d41b Binary files /dev/null and b/RevealStack/RevealStack/Assets.xcassets/Star.imageset/star300.png differ diff --git a/RevealStack/RevealStack/Base.lproj/LaunchScreen.storyboard b/RevealStack/RevealStack/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/RevealStack/RevealStack/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RevealStack/RevealStack/Base.lproj/Main.storyboard b/RevealStack/RevealStack/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d3bf493 --- /dev/null +++ b/RevealStack/RevealStack/Base.lproj/Main.storyboard @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RevealStack/RevealStack/Info.plist b/RevealStack/RevealStack/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/RevealStack/RevealStack/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/RevealStack/RevealStack/RevealViewController.swift b/RevealStack/RevealStack/RevealViewController.swift new file mode 100644 index 0000000..73eaeed --- /dev/null +++ b/RevealStack/RevealStack/RevealViewController.swift @@ -0,0 +1,82 @@ +// +// RevealViewController.swift +// RevealStack +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class RevealViewController: UIViewController { + @IBOutlet private var rootStackView: UIStackView! + @IBOutlet private var imageStackView: UIStackView! + @IBOutlet private var revealSwitch: UISwitch! + + private lazy var coverView: UIView = { + let view = UIView() + view.backgroundColor = .yellow + return view + }() + + private lazy var backgroundView: UIView = { + let view = UIView() + view.backgroundColor = .purple + view.layer.cornerRadius = 10.0 + return view + }() + + @IBAction func revealAction(_ sender: UISwitch) { + UIView.animate(withDuration: 0.25) { + self.configureReveal() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + pinBackground(backgroundView, to: rootStackView) + pinForeground(coverView, to: imageStackView) + configureReveal() + } + + private func configureReveal() { + coverView.alpha = revealSwitch.isOn ? 0 : 1.0 + } + + private func pinBackground(_ view: UIView, to stackView: UIStackView) { + view.translatesAutoresizingMaskIntoConstraints = false + stackView.insertSubview(view, at: 0) + view.pin(to: stackView) + } + + private func pinForeground(_ view: UIView, to stackView: UIStackView) { + view.translatesAutoresizingMaskIntoConstraints = false + stackView.addSubview(view) + view.pin(to: stackView) + } +} diff --git a/RevealStack/RevealStack/UIView+UYLExtensions.swift b/RevealStack/RevealStack/UIView+UYLExtensions.swift new file mode 100644 index 0000000..25b5b9e --- /dev/null +++ b/RevealStack/RevealStack/UIView+UYLExtensions.swift @@ -0,0 +1,44 @@ +// +// UIView+UYLExtensions.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +public extension UIView { + func pin(to view: UIView) { + NSLayoutConstraint.activate([ + leadingAnchor.constraint(equalTo: view.leadingAnchor), + trailingAnchor.constraint(equalTo: view.trailingAnchor), + topAnchor.constraint(equalTo: view.topAnchor), + bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/ScaledFont/README.md b/ScaledFont/README.md new file mode 100644 index 0000000..d54fccd --- /dev/null +++ b/ScaledFont/README.md @@ -0,0 +1,44 @@ +# Scaled Font + +## Using Dynamic Type With Custom Fonts + +An example of using custom fonts with dynamic type making use of the `UIFontMetrics` class introduced with iOS 11. It provides examples using the Noteworthy font which is built-in to iOS and the Noto Serif font which was downloaded from google fonts: + ++ [Noto Serif](https://fonts.google.com/specimen/Noto+Serif?selection.family=Noto+Serif) + +*Refer to LICENSE.txt if you plan on using Noto Serif in a shipping application.* + +**This project requires iOS 11** + +### ScaledFont + +A utility class to help you use custom fonts with dynamic type. + +To use this class you must supply the name of a style dictionary for the font when creating the class. The style dictionary should be stored as a property list file in the main bundle. + +The style dictionary contains an entry for each text style that uses the raw string value for each `UIFontTextStyle` as the key. + +The value of each entry is a dictionary with two keys: + ++ fontName: A String which is the font name. ++ fontSize: A number which is the point size to use at the `.large` content size. + +For example to use a 17 pt Noteworthy-Bold font for the `.headline` style at the `.large` content size: + + + UICTFontTextStyleHeadline + + fontName + Noteworthy-Bold + fontSize + 17 + + + +You do not need to include an entry for every text style but if you try to use a text style that is not included in the dictionary it will fallback to the system preferred font. + +### Further Details + +See the following blog post for further details: + ++ [Using A Custom Font With Dynamic Type](https://useyourloaf.com/blog/using-a-custom-font-with-dynamic-type/) diff --git a/ScaledFont/ScaledFont.xcodeproj/project.pbxproj b/ScaledFont/ScaledFont.xcodeproj/project.pbxproj new file mode 100644 index 0000000..59a6cc6 --- /dev/null +++ b/ScaledFont/ScaledFont.xcodeproj/project.pbxproj @@ -0,0 +1,374 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 537709DB1F4061130041A64F /* Noteworthy.plist in Resources */ = {isa = PBXBuildFile; fileRef = 537919321F3FA0CF00FF9E25 /* Noteworthy.plist */; }; + 537709E21F40B0650041A64F /* NotoSerif-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 537709DE1F40AFD80041A64F /* NotoSerif-Bold.ttf */; }; + 537709E31F40B06B0041A64F /* NotoSerif-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 537709E11F40AFD80041A64F /* NotoSerif-Regular.ttf */; }; + 537709E41F40B06F0041A64F /* NotoSerif-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 537709E01F40AFD80041A64F /* NotoSerif-Italic.ttf */; }; + 537709E61F40B18B0041A64F /* NotoSerif.plist in Resources */ = {isa = PBXBuildFile; fileRef = 537709E51F40B18B0041A64F /* NotoSerif.plist */; }; + 5379191F1F3FA05700FF9E25 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5379191E1F3FA05700FF9E25 /* AppDelegate.swift */; }; + 537919211F3FA05700FF9E25 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537919201F3FA05700FF9E25 /* ViewController.swift */; }; + 537919241F3FA05700FF9E25 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 537919221F3FA05700FF9E25 /* Main.storyboard */; }; + 537919261F3FA05700FF9E25 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 537919251F3FA05700FF9E25 /* Assets.xcassets */; }; + 537919291F3FA05700FF9E25 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 537919271F3FA05700FF9E25 /* LaunchScreen.storyboard */; }; + 537919311F3FA0B500FF9E25 /* ScaledFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537919301F3FA0B500FF9E25 /* ScaledFont.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 537709DD1F40AFD80041A64F /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; + 537709DE1F40AFD80041A64F /* NotoSerif-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSerif-Bold.ttf"; sourceTree = ""; }; + 537709DF1F40AFD80041A64F /* NotoSerif-BoldItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSerif-BoldItalic.ttf"; sourceTree = ""; }; + 537709E01F40AFD80041A64F /* NotoSerif-Italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSerif-Italic.ttf"; sourceTree = ""; }; + 537709E11F40AFD80041A64F /* NotoSerif-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSerif-Regular.ttf"; sourceTree = ""; }; + 537709E51F40B18B0041A64F /* NotoSerif.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = NotoSerif.plist; sourceTree = ""; }; + 537709E71F40F3B80041A64F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 5379191B1F3FA05700FF9E25 /* ScaledFont.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScaledFont.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5379191E1F3FA05700FF9E25 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 537919201F3FA05700FF9E25 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 537919231F3FA05700FF9E25 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 537919251F3FA05700FF9E25 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 537919281F3FA05700FF9E25 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5379192A1F3FA05700FF9E25 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 537919301F3FA0B500FF9E25 /* ScaledFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScaledFont.swift; sourceTree = ""; }; + 537919321F3FA0CF00FF9E25 /* Noteworthy.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Noteworthy.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 537919181F3FA05700FF9E25 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 537709DC1F40AFD80041A64F /* Noto_Serif */ = { + isa = PBXGroup; + children = ( + 537709DD1F40AFD80041A64F /* LICENSE.txt */, + 537709DE1F40AFD80041A64F /* NotoSerif-Bold.ttf */, + 537709DF1F40AFD80041A64F /* NotoSerif-BoldItalic.ttf */, + 537709E01F40AFD80041A64F /* NotoSerif-Italic.ttf */, + 537709E11F40AFD80041A64F /* NotoSerif-Regular.ttf */, + ); + path = Noto_Serif; + sourceTree = ""; + }; + 537919121F3FA05700FF9E25 = { + isa = PBXGroup; + children = ( + 537709E71F40F3B80041A64F /* README.md */, + 5379191D1F3FA05700FF9E25 /* ScaledFont */, + 5379191C1F3FA05700FF9E25 /* Products */, + ); + sourceTree = ""; + }; + 5379191C1F3FA05700FF9E25 /* Products */ = { + isa = PBXGroup; + children = ( + 5379191B1F3FA05700FF9E25 /* ScaledFont.app */, + ); + name = Products; + sourceTree = ""; + }; + 5379191D1F3FA05700FF9E25 /* ScaledFont */ = { + isa = PBXGroup; + children = ( + 537709DC1F40AFD80041A64F /* Noto_Serif */, + 5379191E1F3FA05700FF9E25 /* AppDelegate.swift */, + 537919201F3FA05700FF9E25 /* ViewController.swift */, + 537919301F3FA0B500FF9E25 /* ScaledFont.swift */, + 537919321F3FA0CF00FF9E25 /* Noteworthy.plist */, + 537709E51F40B18B0041A64F /* NotoSerif.plist */, + 537919221F3FA05700FF9E25 /* Main.storyboard */, + 537919251F3FA05700FF9E25 /* Assets.xcassets */, + 537919271F3FA05700FF9E25 /* LaunchScreen.storyboard */, + 5379192A1F3FA05700FF9E25 /* Info.plist */, + ); + path = ScaledFont; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5379191A1F3FA05700FF9E25 /* ScaledFont */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5379192D1F3FA05700FF9E25 /* Build configuration list for PBXNativeTarget "ScaledFont" */; + buildPhases = ( + 537919171F3FA05700FF9E25 /* Sources */, + 537919181F3FA05700FF9E25 /* Frameworks */, + 537919191F3FA05700FF9E25 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ScaledFont; + productName = ScaledFont; + productReference = 5379191B1F3FA05700FF9E25 /* ScaledFont.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 537919131F3FA05700FF9E25 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 0940; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5379191A1F3FA05700FF9E25 = { + CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 1020; + }; + }; + }; + buildConfigurationList = 537919161F3FA05700FF9E25 /* Build configuration list for PBXProject "ScaledFont" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 537919121F3FA05700FF9E25; + productRefGroup = 5379191C1F3FA05700FF9E25 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5379191A1F3FA05700FF9E25 /* ScaledFont */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 537919191F3FA05700FF9E25 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 537919291F3FA05700FF9E25 /* LaunchScreen.storyboard in Resources */, + 537709E31F40B06B0041A64F /* NotoSerif-Regular.ttf in Resources */, + 537709E61F40B18B0041A64F /* NotoSerif.plist in Resources */, + 537709E41F40B06F0041A64F /* NotoSerif-Italic.ttf in Resources */, + 537709DB1F4061130041A64F /* Noteworthy.plist in Resources */, + 537709E21F40B0650041A64F /* NotoSerif-Bold.ttf in Resources */, + 537919261F3FA05700FF9E25 /* Assets.xcassets in Resources */, + 537919241F3FA05700FF9E25 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 537919171F3FA05700FF9E25 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 537919311F3FA0B500FF9E25 /* ScaledFont.swift in Sources */, + 537919211F3FA05700FF9E25 /* ViewController.swift in Sources */, + 5379191F1F3FA05700FF9E25 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 537919221F3FA05700FF9E25 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 537919231F3FA05700FF9E25 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 537919271F3FA05700FF9E25 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 537919281F3FA05700FF9E25 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5379192B1F3FA05700FF9E25 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5379192C1F3FA05700FF9E25 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5379192E1F3FA05700FF9E25 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ScaledFont/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ScaledFont; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5379192F1F3FA05700FF9E25 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ScaledFont/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ScaledFont; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 537919161F3FA05700FF9E25 /* Build configuration list for PBXProject "ScaledFont" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5379192B1F3FA05700FF9E25 /* Debug */, + 5379192C1F3FA05700FF9E25 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5379192D1F3FA05700FF9E25 /* Build configuration list for PBXNativeTarget "ScaledFont" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5379192E1F3FA05700FF9E25 /* Debug */, + 5379192F1F3FA05700FF9E25 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 537919131F3FA05700FF9E25 /* Project object */; +} diff --git a/ScaledFont/ScaledFont/AppDelegate.swift b/ScaledFont/ScaledFont/AppDelegate.swift new file mode 100644 index 0000000..6420758 --- /dev/null +++ b/ScaledFont/ScaledFont/AppDelegate.swift @@ -0,0 +1,35 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/ScaledFont/ScaledFont/Assets.xcassets/AppIcon.appiconset/Contents.json b/ScaledFont/ScaledFont/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/ScaledFont/ScaledFont/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ScaledFont/ScaledFont/Base.lproj/LaunchScreen.storyboard b/ScaledFont/ScaledFont/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f83f6fd --- /dev/null +++ b/ScaledFont/ScaledFont/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScaledFont/ScaledFont/Base.lproj/Main.storyboard b/ScaledFont/ScaledFont/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f995ddd --- /dev/null +++ b/ScaledFont/ScaledFont/Base.lproj/Main.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScaledFont/ScaledFont/Info.plist b/ScaledFont/ScaledFont/Info.plist new file mode 100644 index 0000000..24cd042 --- /dev/null +++ b/ScaledFont/ScaledFont/Info.plist @@ -0,0 +1,52 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIAppFonts + + NotoSerif-Regular.ttf + NotoSerif-Bold.ttf + NotoSerif-Italic.ttf + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ScaledFont/ScaledFont/Noteworthy.plist b/ScaledFont/ScaledFont/Noteworthy.plist new file mode 100644 index 0000000..4395e75 --- /dev/null +++ b/ScaledFont/ScaledFont/Noteworthy.plist @@ -0,0 +1,83 @@ + + + + + UICTFontTextStyleTitle0 + + fontName + Noteworthy-Light + fontSize + 34 + + UICTFontTextStyleTitle1 + + fontName + Noteworthy-Light + fontSize + 28 + + UICTFontTextStyleTitle2 + + fontName + Noteworthy-Light + fontSize + 22 + + UICTFontTextStyleTitle3 + + fontName + Noteworthy-Light + fontSize + 20 + + UICTFontTextStyleHeadline + + fontName + Noteworthy-Bold + fontSize + 17 + + UICTFontTextStyleSubhead + + fontName + Noteworthy-Light + fontSize + 15 + + UICTFontTextStyleBody + + fontName + Noteworthy-Light + fontSize + 17 + + UICTFontTextStyleCallout + + fontName + Noteworthy-Light + fontSize + 16 + + UICTFontTextStyleFootnote + + fontName + Noteworthy-Light + fontSize + 13 + + UICTFontTextStyleCaption1 + + fontName + Noteworthy-Light + fontSize + 12 + + UICTFontTextStyleCaption2 + + fontName + Noteworthy-Light + fontSize + 11 + + + diff --git a/ScaledFont/ScaledFont/NotoSerif.plist b/ScaledFont/ScaledFont/NotoSerif.plist new file mode 100644 index 0000000..2d35c45 --- /dev/null +++ b/ScaledFont/ScaledFont/NotoSerif.plist @@ -0,0 +1,83 @@ + + + + + UICTFontTextStyleTitle0 + + fontName + NotoSerif + fontSize + 34 + + UICTFontTextStyleTitle1 + + fontName + NotoSerif + fontSize + 28 + + UICTFontTextStyleTitle2 + + fontName + NotoSerif + fontSize + 22 + + UICTFontTextStyleTitle3 + + fontName + NotoSerif + fontSize + 20 + + UICTFontTextStyleHeadline + + fontName + NotoSerif-Bold + fontSize + 17 + + UICTFontTextStyleSubhead + + fontName + NotoSerif-Italic + fontSize + 15 + + UICTFontTextStyleBody + + fontName + NotoSerif + fontSize + 17 + + UICTFontTextStyleCallout + + fontName + NotoSerif + fontSize + 16 + + UICTFontTextStyleFootnote + + fontName + NotoSerif + fontSize + 13 + + UICTFontTextStyleCaption1 + + fontName + NotoSerif-Italic + fontSize + 12 + + UICTFontTextStyleCaption2 + + fontName + NotoSerif-Italic + fontSize + 10 + + + diff --git a/ScaledFont/ScaledFont/Noto_Serif/LICENSE.txt b/ScaledFont/ScaledFont/Noto_Serif/LICENSE.txt new file mode 100755 index 0000000..75b5248 --- /dev/null +++ b/ScaledFont/ScaledFont/Noto_Serif/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Bold.ttf b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Bold.ttf new file mode 100755 index 0000000..580ff28 Binary files /dev/null and b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Bold.ttf differ diff --git a/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-BoldItalic.ttf b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-BoldItalic.ttf new file mode 100755 index 0000000..32d38af Binary files /dev/null and b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-BoldItalic.ttf differ diff --git a/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Italic.ttf b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Italic.ttf new file mode 100755 index 0000000..1d3cc3a Binary files /dev/null and b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Italic.ttf differ diff --git a/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Regular.ttf b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Regular.ttf new file mode 100755 index 0000000..a1c6f10 Binary files /dev/null and b/ScaledFont/ScaledFont/Noto_Serif/NotoSerif-Regular.ttf differ diff --git a/ScaledFont/ScaledFont/ScaledFont.swift b/ScaledFont/ScaledFont/ScaledFont.swift new file mode 100644 index 0000000..09b8b81 --- /dev/null +++ b/ScaledFont/ScaledFont/ScaledFont.swift @@ -0,0 +1,113 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +/// A utility class to help you use custom fonts with +/// dynamic type. +/// +/// To use this class you must supply the name of a style +/// dictionary for the font when creating the class. The +/// style dictionary should be stored as a property list +/// file in the main bundle. +/// +/// The style dictionary contains an entry for each text +/// style that uses the raw string value for each +/// `UIFontTextStyle` as the key. +/// +/// The value of each entry is a dictionary with two keys: +/// +/// + fontName: A String which is the font name. +/// + fontSize: A number which is the point size to use +/// at the `.large` content size. +/// +/// For example to use a 17 pt Noteworthy-Bold font +/// for the `.headline` style at the `.large` content size: +/// +/// +/// UICTFontTextStyleHeadline +/// +/// fontName +/// Noteworthy-Bold +/// fontSize +/// 17 +/// +/// +/// +/// You do not need to include an entry for every text style +/// but if you try to use a text style that is not included +/// in the dictionary it will fallback to the system preferred +/// font. + +public final class ScaledFont { + private struct FontDescription: Decodable { + let fontSize: CGFloat + let fontName: String + } + + private typealias StyleDictionary = [UIFont.TextStyle.RawValue: FontDescription] + private var styleDictionary: StyleDictionary? + + /// Create a `ScaledFont` + /// + /// - Parameter fontName: Name of a plist file (without the extension) + /// in the main bundle that contains the style dictionary used to + /// scale fonts for each text style. + + public init(fontName: String) { + if let url = Bundle.main.url(forResource: fontName, withExtension: "plist"), + let data = try? Data(contentsOf: url) { + let decoder = PropertyListDecoder() + styleDictionary = try? decoder.decode(StyleDictionary.self, from: data) + } + } + + /// Get the scaled font for the given text style using the + /// style dictionary supplied at initialization. + /// + /// - Parameter textStyle: The `UIFontTextStyle` for the + /// font. + /// - Returns: A `UIFont` of the custom font that has been + /// scaled for the users currently selected preferred + /// text size. + /// + /// - Note: If the style dictionary does not have + /// a font for this text style the default preferred + /// font is returned. + + public func font(forTextStyle textStyle: UIFont.TextStyle) -> UIFont { + guard let fontDescription = styleDictionary?[textStyle.rawValue], + let font = UIFont(name: fontDescription.fontName, size: fontDescription.fontSize) else { + return UIFont.preferredFont(forTextStyle: textStyle) + } + + let fontMetrics = UIFontMetrics(forTextStyle: textStyle) + return fontMetrics.scaledFont(for: font) + } +} diff --git a/ScaledFont/ScaledFont/ViewController.swift b/ScaledFont/ScaledFont/ViewController.swift new file mode 100644 index 0000000..315a7fd --- /dev/null +++ b/ScaledFont/ScaledFont/ViewController.swift @@ -0,0 +1,124 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class ViewController: UIViewController { +// private let fontName = "Default" +// private let fontName = "Noteworthy" + private let fontName = "NotoSerif" + + private let defaultSpacing: CGFloat = 8.0 + + private lazy var scaledFont: ScaledFont = { + ScaledFont(fontName: fontName) + }() + + override func viewDidLoad() { + super.viewDidLoad() + title = fontName + setupViews() + } + + private lazy var title1Label: UILabel = { + label(forTextStyle: .title1, text: "Title 1") + }() + + private lazy var title2Label: UILabel = { + label(forTextStyle: .title2, text: "Title 2") + }() + + private lazy var title3Label: UILabel = { + label(forTextStyle: .title3, text: "Title 3") + }() + + private lazy var headlineLabel: UILabel = { + label(forTextStyle: .headline, text: "Headline") + }() + + private lazy var subheadlineLabel: UILabel = { + label(forTextStyle: .subheadline, text: "Subheadline") + }() + + private lazy var bodyLabel: UILabel = { + label(forTextStyle: .body, text: "Body") + }() + + private lazy var calloutLabel: UILabel = { + label(forTextStyle: .callout, text: "Callout") + }() + + private lazy var footnoteLabel: UILabel = { + label(forTextStyle: .footnote, text: "Footnote") + }() + + private lazy var caption1Label: UILabel = { + label(forTextStyle: .caption1, text: "Caption 1") + }() + + private lazy var caption2Label: UILabel = { + label(forTextStyle: .caption2, text: "Caption 2") + }() + + private func label(forTextStyle textStyle: UIFont.TextStyle, text: String) -> UILabel { + let label = UILabel() + label.font = scaledFont.font(forTextStyle: textStyle) + label.adjustsFontForContentSizeCategory = true + label.text = text + label.numberOfLines = 0 + return label + } + + private func setupViews() { + let stackView = UIStackView(arrangedSubviews: [title1Label, title2Label, title3Label, headlineLabel, subheadlineLabel, bodyLabel, calloutLabel, footnoteLabel, caption1Label, caption2Label]) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.spacing = defaultSpacing + stackView.axis = .vertical + + let scrollView = UIScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.addSubview(stackView) + view.addSubview(scrollView) + + let margins = view.readableContentGuide + NSLayoutConstraint.activate([ + scrollView.topAnchor.constraint(equalTo: margins.topAnchor), + scrollView.bottomAnchor.constraint(equalTo: margins.bottomAnchor), + scrollView.leadingAnchor.constraint(equalTo: margins.leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: margins.trailingAnchor), + + scrollView.topAnchor.constraint(equalTo: stackView.topAnchor), + scrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor), + scrollView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor), + + scrollView.widthAnchor.constraint(equalTo: stackView.widthAnchor) + ]) + } +} diff --git a/ScrollGuide-IB/README.md b/ScrollGuide-IB/README.md new file mode 100644 index 0000000..5193288 --- /dev/null +++ b/ScrollGuide-IB/README.md @@ -0,0 +1,9 @@ +# Scroll View Layout Guides + +Xcode 11 adds direct support for the content layout guides of a `UIScrollView` to Interface Builder. See the following post for details: + ++ [Scroll View Layouts With Interface Builder](https://useyourloaf.com/blog/scroll-view-layouts-with-interface-builder/) + +You can compare the Interface Builder version of the layout with the progammatic version described in this earlier post: + ++ [Easier Scrolling With Layout Guides](https://useyourloaf.com/blog/easier-scrolling-with-layout-guides/) diff --git a/ScrollGuide-IB/ScrollGuide-IB.xcodeproj/project.pbxproj b/ScrollGuide-IB/ScrollGuide-IB.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5622ba2 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB.xcodeproj/project.pbxproj @@ -0,0 +1,345 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 537CC979232BD70800424444 /* ForecastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537CC978232BD70800424444 /* ForecastViewController.swift */; }; + 537CC97B232BD80300424444 /* Forecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537CC97A232BD80300424444 /* Forecast.swift */; }; + 53926B86232BD49B0070DCB1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53926B85232BD49B0070DCB1 /* AppDelegate.swift */; }; + 53926B8D232BD49B0070DCB1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53926B8B232BD49B0070DCB1 /* Main.storyboard */; }; + 53926B8F232BD49B0070DCB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53926B8E232BD49B0070DCB1 /* Assets.xcassets */; }; + 53926B92232BD49B0070DCB1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53926B90232BD49B0070DCB1 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 537CC978232BD70800424444 /* ForecastViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastViewController.swift; sourceTree = ""; }; + 537CC97A232BD80300424444 /* Forecast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Forecast.swift; sourceTree = ""; }; + 537CC99C23301D1800424444 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53926B82232BD49B0070DCB1 /* ScrollGuide-IB.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ScrollGuide-IB.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 53926B85232BD49B0070DCB1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53926B8C232BD49B0070DCB1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53926B8E232BD49B0070DCB1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53926B91232BD49B0070DCB1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53926B93232BD49B0070DCB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53926B7F232BD49B0070DCB1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53926B79232BD49B0070DCB1 = { + isa = PBXGroup; + children = ( + 537CC99C23301D1800424444 /* README.md */, + 53926B84232BD49B0070DCB1 /* ScrollGuide-IB */, + 53926B83232BD49B0070DCB1 /* Products */, + ); + sourceTree = ""; + }; + 53926B83232BD49B0070DCB1 /* Products */ = { + isa = PBXGroup; + children = ( + 53926B82232BD49B0070DCB1 /* ScrollGuide-IB.app */, + ); + name = Products; + sourceTree = ""; + }; + 53926B84232BD49B0070DCB1 /* ScrollGuide-IB */ = { + isa = PBXGroup; + children = ( + 537CC978232BD70800424444 /* ForecastViewController.swift */, + 537CC97A232BD80300424444 /* Forecast.swift */, + 53926B85232BD49B0070DCB1 /* AppDelegate.swift */, + 53926B8B232BD49B0070DCB1 /* Main.storyboard */, + 53926B8E232BD49B0070DCB1 /* Assets.xcassets */, + 53926B90232BD49B0070DCB1 /* LaunchScreen.storyboard */, + 53926B93232BD49B0070DCB1 /* Info.plist */, + ); + path = "ScrollGuide-IB"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53926B81232BD49B0070DCB1 /* ScrollGuide-IB */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53926B96232BD49B0070DCB1 /* Build configuration list for PBXNativeTarget "ScrollGuide-IB" */; + buildPhases = ( + 53926B7E232BD49B0070DCB1 /* Sources */, + 53926B7F232BD49B0070DCB1 /* Frameworks */, + 53926B80232BD49B0070DCB1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ScrollGuide-IB"; + productName = "ScrollGuide-IB"; + productReference = 53926B82232BD49B0070DCB1 /* ScrollGuide-IB.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53926B7A232BD49B0070DCB1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53926B81232BD49B0070DCB1 = { + CreatedOnToolsVersion = 11.0; + }; + }; + }; + buildConfigurationList = 53926B7D232BD49B0070DCB1 /* Build configuration list for PBXProject "ScrollGuide-IB" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53926B79232BD49B0070DCB1; + productRefGroup = 53926B83232BD49B0070DCB1 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53926B81232BD49B0070DCB1 /* ScrollGuide-IB */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53926B80232BD49B0070DCB1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53926B92232BD49B0070DCB1 /* LaunchScreen.storyboard in Resources */, + 53926B8F232BD49B0070DCB1 /* Assets.xcassets in Resources */, + 53926B8D232BD49B0070DCB1 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53926B7E232BD49B0070DCB1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53926B86232BD49B0070DCB1 /* AppDelegate.swift in Sources */, + 537CC97B232BD80300424444 /* Forecast.swift in Sources */, + 537CC979232BD70800424444 /* ForecastViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53926B8B232BD49B0070DCB1 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53926B8C232BD49B0070DCB1 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53926B90232BD49B0070DCB1 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53926B91232BD49B0070DCB1 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53926B94232BD49B0070DCB1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53926B95232BD49B0070DCB1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53926B97232BD49B0070DCB1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = "ScrollGuide-IB/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.ScrollGuide-IB"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53926B98232BD49B0070DCB1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = "ScrollGuide-IB/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.ScrollGuide-IB"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53926B7D232BD49B0070DCB1 /* Build configuration list for PBXProject "ScrollGuide-IB" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53926B94232BD49B0070DCB1 /* Debug */, + 53926B95232BD49B0070DCB1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53926B96232BD49B0070DCB1 /* Build configuration list for PBXNativeTarget "ScrollGuide-IB" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53926B97232BD49B0070DCB1 /* Debug */, + 53926B98232BD49B0070DCB1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53926B7A232BD49B0070DCB1 /* Project object */; +} diff --git a/ScrollGuide-IB/ScrollGuide-IB/AppDelegate.swift b/ScrollGuide-IB/ScrollGuide-IB/AppDelegate.swift new file mode 100644 index 0000000..a95b2c1 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/AppDelegate.swift @@ -0,0 +1,43 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + if let navigationController = window?.rootViewController as? UINavigationController, + let forecastViewController = navigationController.topViewController as? ForecastViewController { + let forecast = Forecast(title: "Weather For Today", condition: .sun, summary: "Today will be hot and sunny. If you are going out you will need a hat and sunglasses. There is a small chance of a heavy thunderstorm in the afternoon that could cause severe flooding so you may also want to take a boat.") + forecastViewController.forecast = forecast + } + return true + } +} diff --git a/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/AppIcon.appiconset/Contents.json b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Contents.json b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/SkyBlue.colorset/Contents.json b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/SkyBlue.colorset/Contents.json new file mode 100644 index 0000000..1f49b00 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/SkyBlue.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.463", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.835" + } + } + } + ] +} \ No newline at end of file diff --git a/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Contents.json b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Contents.json new file mode 100644 index 0000000..d73dd65 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Sun150.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Sun150.pdf b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Sun150.pdf new file mode 100644 index 0000000..0715bf8 Binary files /dev/null and b/ScrollGuide-IB/ScrollGuide-IB/Assets.xcassets/Sun.imageset/Sun150.pdf differ diff --git a/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/LaunchScreen.storyboard b/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fc2d48c --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/Main.storyboard b/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/Main.storyboard new file mode 100644 index 0000000..a0fc3ec --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Base.lproj/Main.storyboard @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScrollGuide-IB/ScrollGuide-IB/Forecast.swift b/ScrollGuide-IB/ScrollGuide-IB/Forecast.swift new file mode 100644 index 0000000..a36cd4d --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Forecast.swift @@ -0,0 +1,49 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +public struct Forecast { + public enum Condition { + case sun + // other conditions... + } + + let title: String + let condition: Condition + let summary: String +} + +public extension Forecast { + func icon() -> UIImage { + switch condition { + case .sun: return UIImage(named: "Sun")! + // other conditions... + } + } +} diff --git a/ScrollGuide-IB/ScrollGuide-IB/ForecastViewController.swift b/ScrollGuide-IB/ScrollGuide-IB/ForecastViewController.swift new file mode 100644 index 0000000..35e972a --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/ForecastViewController.swift @@ -0,0 +1,57 @@ +// Copyright © 2019 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ForecastViewController: UIViewController { + @IBOutlet private var titleLabel: UILabel? + @IBOutlet private var summaryLabel: UILabel? + @IBOutlet private var imageView: UIImageView? + + var forecast: Forecast? { didSet { updateView() } } + + private func updateView() { + if let forecast = forecast { + titleLabel?.text = forecast.title + summaryLabel?.text = forecast.summary + imageView?.image = forecast.icon() + imageView?.sizeToFit() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + updateView() + } +} + +extension ForecastViewController { + @IBAction private func showInfo(_ sender: UIButton) { + print("Show Info") + } +} diff --git a/ScrollGuide-IB/ScrollGuide-IB/Info.plist b/ScrollGuide-IB/ScrollGuide-IB/Info.plist new file mode 100644 index 0000000..8f416d0 --- /dev/null +++ b/ScrollGuide-IB/ScrollGuide-IB/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ScrollGuide/README.md b/ScrollGuide/README.md new file mode 100644 index 0000000..73909f2 --- /dev/null +++ b/ScrollGuide/README.md @@ -0,0 +1,9 @@ +# Scroll View Layout Guides + +An example of using the two new layout guides added to `UIScrollView` in iOS 11. See the following post for details: + ++ [Easier Scrolling With Layout Guides](https://useyourloaf.com/blog/easier-scrolling-with-layout-guides/) + +Starting with Xcode 11 the content layout guides are available in Interface Builder. See this later post for a version of this layout built entirely with Interface Builder: + ++ [Scroll View Layouts With Interface Builder](https://useyourloaf.com/blog/scroll-view-layouts-with-interface-builder/) diff --git a/ScrollGuide/ScrollGuide.xcodeproj/project.pbxproj b/ScrollGuide/ScrollGuide.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d35b6dd --- /dev/null +++ b/ScrollGuide/ScrollGuide.xcodeproj/project.pbxproj @@ -0,0 +1,344 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 53FD5C342126C480008DA03A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FD5C332126C480008DA03A /* AppDelegate.swift */; }; + 53FD5C382126C481008DA03A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53FD5C372126C481008DA03A /* Assets.xcassets */; }; + 53FD5C3B2126C481008DA03A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53FD5C392126C481008DA03A /* LaunchScreen.storyboard */; }; + 53FD5C432126C514008DA03A /* ForecastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FD5C422126C514008DA03A /* ForecastViewController.swift */; }; + 53FD5C452126C533008DA03A /* ForecastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FD5C442126C533008DA03A /* ForecastView.swift */; }; + 53FD5C492126C5DA008DA03A /* Forecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FD5C482126C5DA008DA03A /* Forecast.swift */; }; + 53FD5C4B2126C617008DA03A /* UILabel+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FD5C4A2126C617008DA03A /* UILabel+Style.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53B5CE7C212AEBDA00FF5FCB /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53FD5C302126C480008DA03A /* ScrollGuide.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScrollGuide.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53FD5C332126C480008DA03A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53FD5C372126C481008DA03A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53FD5C3A2126C481008DA03A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53FD5C3C2126C481008DA03A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53FD5C422126C514008DA03A /* ForecastViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastViewController.swift; sourceTree = ""; }; + 53FD5C442126C533008DA03A /* ForecastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastView.swift; sourceTree = ""; }; + 53FD5C482126C5DA008DA03A /* Forecast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Forecast.swift; sourceTree = ""; }; + 53FD5C4A2126C617008DA03A /* UILabel+Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+Style.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53FD5C2D2126C480008DA03A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53FD5C272126C480008DA03A = { + isa = PBXGroup; + children = ( + 53B5CE7C212AEBDA00FF5FCB /* README.md */, + 53FD5C322126C480008DA03A /* ScrollGuide */, + 53FD5C312126C480008DA03A /* Products */, + ); + sourceTree = ""; + }; + 53FD5C312126C480008DA03A /* Products */ = { + isa = PBXGroup; + children = ( + 53FD5C302126C480008DA03A /* ScrollGuide.app */, + ); + name = Products; + sourceTree = ""; + }; + 53FD5C322126C480008DA03A /* ScrollGuide */ = { + isa = PBXGroup; + children = ( + 53FD5C4A2126C617008DA03A /* UILabel+Style.swift */, + 53FD5C332126C480008DA03A /* AppDelegate.swift */, + 53FD5C422126C514008DA03A /* ForecastViewController.swift */, + 53FD5C442126C533008DA03A /* ForecastView.swift */, + 53FD5C482126C5DA008DA03A /* Forecast.swift */, + 53FD5C372126C481008DA03A /* Assets.xcassets */, + 53FD5C392126C481008DA03A /* LaunchScreen.storyboard */, + 53FD5C3C2126C481008DA03A /* Info.plist */, + ); + path = ScrollGuide; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53FD5C2F2126C480008DA03A /* ScrollGuide */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53FD5C3F2126C481008DA03A /* Build configuration list for PBXNativeTarget "ScrollGuide" */; + buildPhases = ( + 53FD5C2C2126C480008DA03A /* Sources */, + 53FD5C2D2126C480008DA03A /* Frameworks */, + 53FD5C2E2126C480008DA03A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ScrollGuide; + productName = ScrollGuide; + productReference = 53FD5C302126C480008DA03A /* ScrollGuide.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53FD5C282126C480008DA03A /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53FD5C2F2126C480008DA03A = { + CreatedOnToolsVersion = 10.0; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 53FD5C2B2126C480008DA03A /* Build configuration list for PBXProject "ScrollGuide" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53FD5C272126C480008DA03A; + productRefGroup = 53FD5C312126C480008DA03A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53FD5C2F2126C480008DA03A /* ScrollGuide */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53FD5C2E2126C480008DA03A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53FD5C382126C481008DA03A /* Assets.xcassets in Resources */, + 53FD5C3B2126C481008DA03A /* LaunchScreen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53FD5C2C2126C480008DA03A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53FD5C342126C480008DA03A /* AppDelegate.swift in Sources */, + 53FD5C432126C514008DA03A /* ForecastViewController.swift in Sources */, + 53FD5C4B2126C617008DA03A /* UILabel+Style.swift in Sources */, + 53FD5C452126C533008DA03A /* ForecastView.swift in Sources */, + 53FD5C492126C5DA008DA03A /* Forecast.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53FD5C392126C481008DA03A /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53FD5C3A2126C481008DA03A /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53FD5C3D2126C481008DA03A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53FD5C3E2126C481008DA03A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53FD5C402126C481008DA03A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ScrollGuide/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ScrollGuide; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53FD5C412126C481008DA03A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = ScrollGuide/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.ScrollGuide; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53FD5C2B2126C480008DA03A /* Build configuration list for PBXProject "ScrollGuide" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53FD5C3D2126C481008DA03A /* Debug */, + 53FD5C3E2126C481008DA03A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53FD5C3F2126C481008DA03A /* Build configuration list for PBXNativeTarget "ScrollGuide" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53FD5C402126C481008DA03A /* Debug */, + 53FD5C412126C481008DA03A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53FD5C282126C480008DA03A /* Project object */; +} diff --git a/ScrollGuide/ScrollGuide/AppDelegate.swift b/ScrollGuide/ScrollGuide/AppDelegate.swift new file mode 100644 index 0000000..071c8dd --- /dev/null +++ b/ScrollGuide/ScrollGuide/AppDelegate.swift @@ -0,0 +1,50 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + window?.backgroundColor = .white + + let forecastViewController = ForecastViewController() + forecastViewController.title = NSLocalizedString("Forecast", comment: "Forecast") + let forecast = Forecast(title: "Weather For Today", condition: .sun, summary: "Today will be hot and sunny. If you are going out you will need a hat and sunglasses. There is a small chance of a heavy thunderstorm in the afternoon that could cause severe flooding so you may also want to take a boat.") + forecastViewController.forecast = forecast + + let navigationController = UINavigationController(rootViewController: forecastViewController) + window?.rootViewController = navigationController + window?.makeKeyAndVisible() + return true + } +} diff --git a/ScrollGuide/ScrollGuide/Assets.xcassets/AppIcon.appiconset/Contents.json b/ScrollGuide/ScrollGuide/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ScrollGuide/ScrollGuide/Assets.xcassets/Contents.json b/ScrollGuide/ScrollGuide/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ScrollGuide/ScrollGuide/Assets.xcassets/SkyBlue.colorset/Contents.json b/ScrollGuide/ScrollGuide/Assets.xcassets/SkyBlue.colorset/Contents.json new file mode 100644 index 0000000..e039289 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Assets.xcassets/SkyBlue.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.463", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.839" + } + } + } + ] +} \ No newline at end of file diff --git a/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Contents.json b/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Contents.json new file mode 100644 index 0000000..d73dd65 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Sun150.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Sun150.pdf b/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Sun150.pdf new file mode 100644 index 0000000..0715bf8 Binary files /dev/null and b/ScrollGuide/ScrollGuide/Assets.xcassets/Sun.imageset/Sun150.pdf differ diff --git a/ScrollGuide/ScrollGuide/Base.lproj/LaunchScreen.storyboard b/ScrollGuide/ScrollGuide/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ScrollGuide/ScrollGuide/Forecast.swift b/ScrollGuide/ScrollGuide/Forecast.swift new file mode 100644 index 0000000..691ebc2 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Forecast.swift @@ -0,0 +1,50 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +public struct Forecast { + + public enum Condition { + case sun + // other conditions... + } + + let title: String + let condition: Condition + let summary: String +} + +public extension Forecast { + func icon() -> UIImage { + switch condition { + case .sun: return UIImage(named: "Sun")! + // other conditions... + } + } +} diff --git a/ScrollGuide/ScrollGuide/ForecastView.swift b/ScrollGuide/ScrollGuide/ForecastView.swift new file mode 100644 index 0000000..1ef4a53 --- /dev/null +++ b/ScrollGuide/ScrollGuide/ForecastView.swift @@ -0,0 +1,81 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ForecastView: UIView { + + let titleLabel: UILabel = { + let label = UILabel.makeLabel(forTextStyle: .title1) + label.textAlignment = .center + return label + }() + + let imageView: UIImageView = { + let view = UIImageView() + view.translatesAutoresizingMaskIntoConstraints = false + view.setContentHuggingPriority(.defaultLow + 1, for: .horizontal) + view.setContentCompressionResistancePriority(.defaultHigh + 1, for: .horizontal) + return view + }() + + let summaryLabel: UILabel = { + return UILabel.makeLabel(forTextStyle: .body) + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupView() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupView() + } + + private func setupView() { + addSubview(titleLabel) + addSubview(summaryLabel) + addSubview(imageView) + + let margin = readableContentGuide + NSLayoutConstraint.activate([ + titleLabel.leadingAnchor.constraint(equalTo: margin.leadingAnchor), + titleLabel.topAnchor.constraint(equalTo: margin.topAnchor), + titleLabel.trailingAnchor.constraint(equalTo: margin.trailingAnchor), + + imageView.centerXAnchor.constraint(equalTo: margin.centerXAnchor), + imageView.topAnchor.constraint(equalToSystemSpacingBelow: titleLabel.bottomAnchor, multiplier: 1.0), + + summaryLabel.leadingAnchor.constraint(equalTo: margin.leadingAnchor), + summaryLabel.topAnchor.constraint(equalToSystemSpacingBelow: imageView.bottomAnchor, multiplier: 1.0), + summaryLabel.trailingAnchor.constraint(equalTo: margin.trailingAnchor), + summaryLabel.bottomAnchor.constraint(equalTo: margin.bottomAnchor) + ]) + } +} diff --git a/ScrollGuide/ScrollGuide/ForecastViewController.swift b/ScrollGuide/ScrollGuide/ForecastViewController.swift new file mode 100644 index 0000000..8b2f1e0 --- /dev/null +++ b/ScrollGuide/ScrollGuide/ForecastViewController.swift @@ -0,0 +1,125 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ForecastViewController: UIViewController { + + private enum ViewMetrics { + static let margin: CGFloat = 20.0 + static let backgroundColor = UIColor(named: "SkyBlue") + } + + private let forecastView: ForecastView = { + let view = ForecastView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = ViewMetrics.backgroundColor + return view + }() + + private lazy var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.addSubview(forecastView) + return scrollView + }() + + private let infoButton: UIButton = { + let button = UIButton(type: .infoDark) + button.translatesAutoresizingMaskIntoConstraints = false + button.addTarget(self, action: #selector(showInfo(_:)), for: .touchUpInside) + return button + }() + + var forecast: Forecast? { didSet { updateView() } } + + private func updateView() { + if let forecast = forecast { + forecastView.titleLabel.text = forecast.title + forecastView.summaryLabel.text = forecast.summary + forecastView.imageView.image = forecast.icon() + forecastView.imageView.sizeToFit() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + updateView() + } + + private func setupView() { + view.backgroundColor = ViewMetrics.backgroundColor + forecastView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: ViewMetrics.margin, leading: ViewMetrics.margin, bottom: ViewMetrics.margin, trailing: ViewMetrics.margin) + view.addSubview(scrollView) + + scrollView.addSubview(infoButton) + + let frameGuide = scrollView.frameLayoutGuide + let contentGuide = scrollView.contentLayoutGuide + + // Classic scroll view setup using scroll view anchors +// NSLayoutConstraint.activate([ +// scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), +// scrollView.topAnchor.constraint(equalTo: view.topAnchor), +// scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), +// scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), +// +// scrollView.leadingAnchor.constraint(equalTo: forecastView.leadingAnchor), +// scrollView.topAnchor.constraint(equalTo: forecastView.topAnchor), +// scrollView.trailingAnchor.constraint(equalTo: forecastView.trailingAnchor), +// scrollView.bottomAnchor.constraint(equalTo: forecastView.bottomAnchor), +// +// forecastView.widthAnchor.constraint(equalTo: scrollView.widthAnchor) +// ]) + + // Scroll view layout guides (iOS 11) + NSLayoutConstraint.activate([ + frameGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor), + frameGuide.topAnchor.constraint(equalTo: view.topAnchor), + frameGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor), + frameGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor), + + contentGuide.leadingAnchor.constraint(equalTo: forecastView.leadingAnchor), + contentGuide.topAnchor.constraint(equalTo: forecastView.topAnchor), + contentGuide.trailingAnchor.constraint(equalTo: forecastView.trailingAnchor), + contentGuide.bottomAnchor.constraint(equalTo: forecastView.bottomAnchor), + + contentGuide.widthAnchor.constraint(equalTo: frameGuide.widthAnchor), + + infoButton.leadingAnchor.constraint(equalTo: scrollView.layoutMarginsGuide.leadingAnchor), + infoButton.topAnchor.constraint(equalTo: scrollView.layoutMarginsGuide.topAnchor) + ]) + } +} + +extension ForecastViewController { + @objc private func showInfo(_ sender: UIButton) { + print("Show Info") + } +} diff --git a/ScrollGuide/ScrollGuide/Info.plist b/ScrollGuide/ScrollGuide/Info.plist new file mode 100644 index 0000000..e39ce31 --- /dev/null +++ b/ScrollGuide/ScrollGuide/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 2 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ScrollGuide/ScrollGuide/UILabel+Style.swift b/ScrollGuide/ScrollGuide/UILabel+Style.swift new file mode 100644 index 0000000..b1ca3b3 --- /dev/null +++ b/ScrollGuide/ScrollGuide/UILabel+Style.swift @@ -0,0 +1,40 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +extension UILabel { + static func makeLabel(forTextStyle style: UIFont.TextStyle) -> UILabel { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.preferredFont(forTextStyle: style) + label.adjustsFontForContentSizeCategory = true + label.numberOfLines = 0 + return label + } +} diff --git a/SelfSize/README b/SelfSize/README new file mode 100644 index 0000000..9a6664e --- /dev/null +++ b/SelfSize/README @@ -0,0 +1,15 @@ +======================================================================= +SelfSize - Self-sizing table view cells with varying row heights +Version 1.0 07 August 2014 Initial version. +======================================================================= + +Example of using self-sizing table view cells and universal storyboards +introduced in iOS 8. This is a reworking of the Huckleberry project removing +code that is no longer required. The full details are in the following post: + +https://useyourloaf.com/blog/self-sizing-table-view-cells/ + +The original post can also be found here: + +https://useyourloaf.com/blog/table-view-cells-with-varying-row-heights/ + diff --git a/SelfSize/SelfSize.xcodeproj/project.pbxproj b/SelfSize/SelfSize.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f6033cc --- /dev/null +++ b/SelfSize/SelfSize.xcodeproj/project.pbxproj @@ -0,0 +1,341 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 5325894A23C91363008ABE63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5325894923C91363008ABE63 /* LaunchScreen.storyboard */; }; + 5351AA8A19845210006179CA /* README in Resources */ = {isa = PBXBuildFile; fileRef = 5351AA8919845210006179CA /* README */; }; + 53EDDFCA19819CC40064D44A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDDFC919819CC40064D44A /* main.m */; }; + 53EDDFCD19819CC40064D44A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDDFCC19819CC40064D44A /* AppDelegate.m */; }; + 53EDDFD319819CC40064D44A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53EDDFD119819CC40064D44A /* Main.storyboard */; }; + 53EDDFD519819CC40064D44A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53EDDFD419819CC40064D44A /* Images.xcassets */; }; + 53EDDFEC19819D190064D44A /* UYLTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDDFEB19819D190064D44A /* UYLTableViewController.m */; }; + 53EDDFF319819E1C0064D44A /* UYLTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDDFF219819E1C0064D44A /* UYLTextCell.m */; }; + 53EDDFF519819FFC0064D44A /* SourceData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 53EDDFF419819FFC0064D44A /* SourceData.plist */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5325894923C91363008ABE63 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5351AA8919845210006179CA /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + 53EDDFC419819CC40064D44A /* SelfSize.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SelfSize.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53EDDFC819819CC40064D44A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53EDDFC919819CC40064D44A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 53EDDFCB19819CC40064D44A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 53EDDFCC19819CC40064D44A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 53EDDFD219819CC40064D44A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53EDDFD419819CC40064D44A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53EDDFEA19819D190064D44A /* UYLTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTableViewController.h; sourceTree = ""; }; + 53EDDFEB19819D190064D44A /* UYLTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTableViewController.m; sourceTree = ""; }; + 53EDDFF119819E1C0064D44A /* UYLTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLTextCell.h; sourceTree = ""; }; + 53EDDFF219819E1C0064D44A /* UYLTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLTextCell.m; sourceTree = ""; }; + 53EDDFF419819FFC0064D44A /* SourceData.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SourceData.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53EDDFC119819CC40064D44A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53EDDFBB19819CC40064D44A = { + isa = PBXGroup; + children = ( + 5351AA8919845210006179CA /* README */, + 53EDDFC619819CC40064D44A /* SelfSize */, + 53EDDFC519819CC40064D44A /* Products */, + ); + sourceTree = ""; + }; + 53EDDFC519819CC40064D44A /* Products */ = { + isa = PBXGroup; + children = ( + 53EDDFC419819CC40064D44A /* SelfSize.app */, + ); + name = Products; + sourceTree = ""; + }; + 53EDDFC619819CC40064D44A /* SelfSize */ = { + isa = PBXGroup; + children = ( + 53EDDFCB19819CC40064D44A /* AppDelegate.h */, + 53EDDFCC19819CC40064D44A /* AppDelegate.m */, + 53EDDFEA19819D190064D44A /* UYLTableViewController.h */, + 53EDDFEB19819D190064D44A /* UYLTableViewController.m */, + 53EDDFF119819E1C0064D44A /* UYLTextCell.h */, + 53EDDFF219819E1C0064D44A /* UYLTextCell.m */, + 53EDDFD119819CC40064D44A /* Main.storyboard */, + 5325894923C91363008ABE63 /* LaunchScreen.storyboard */, + 53EDDFD419819CC40064D44A /* Images.xcassets */, + 53EDDFC719819CC40064D44A /* Supporting Files */, + ); + path = SelfSize; + sourceTree = ""; + }; + 53EDDFC719819CC40064D44A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53EDDFF419819FFC0064D44A /* SourceData.plist */, + 53EDDFC819819CC40064D44A /* Info.plist */, + 53EDDFC919819CC40064D44A /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53EDDFC319819CC40064D44A /* SelfSize */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53EDDFE419819CC40064D44A /* Build configuration list for PBXNativeTarget "SelfSize" */; + buildPhases = ( + 53EDDFC019819CC40064D44A /* Sources */, + 53EDDFC119819CC40064D44A /* Frameworks */, + 53EDDFC219819CC40064D44A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SelfSize; + productName = SelfSize; + productReference = 53EDDFC419819CC40064D44A /* SelfSize.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53EDDFBC19819CC40064D44A /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53EDDFC319819CC40064D44A = { + CreatedOnToolsVersion = 6.0; + }; + }; + }; + buildConfigurationList = 53EDDFBF19819CC40064D44A /* Build configuration list for PBXProject "SelfSize" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53EDDFBB19819CC40064D44A; + productRefGroup = 53EDDFC519819CC40064D44A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53EDDFC319819CC40064D44A /* SelfSize */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53EDDFC219819CC40064D44A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5351AA8A19845210006179CA /* README in Resources */, + 53EDDFD319819CC40064D44A /* Main.storyboard in Resources */, + 53EDDFD519819CC40064D44A /* Images.xcassets in Resources */, + 5325894A23C91363008ABE63 /* LaunchScreen.storyboard in Resources */, + 53EDDFF519819FFC0064D44A /* SourceData.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53EDDFC019819CC40064D44A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53EDDFCD19819CC40064D44A /* AppDelegate.m in Sources */, + 53EDDFF319819E1C0064D44A /* UYLTextCell.m in Sources */, + 53EDDFEC19819D190064D44A /* UYLTableViewController.m in Sources */, + 53EDDFCA19819CC40064D44A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53EDDFD119819CC40064D44A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53EDDFD219819CC40064D44A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53EDDFE219819CC40064D44A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53EDDFE319819CC40064D44A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53EDDFE519819CC40064D44A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = SelfSize/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 53EDDFE619819CC40064D44A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = SelfSize/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53EDDFBF19819CC40064D44A /* Build configuration list for PBXProject "SelfSize" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53EDDFE219819CC40064D44A /* Debug */, + 53EDDFE319819CC40064D44A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53EDDFE419819CC40064D44A /* Build configuration list for PBXNativeTarget "SelfSize" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53EDDFE519819CC40064D44A /* Debug */, + 53EDDFE619819CC40064D44A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53EDDFBC19819CC40064D44A /* Project object */; +} diff --git a/SelfSize/SelfSize/AppDelegate.h b/SelfSize/SelfSize/AppDelegate.h new file mode 100644 index 0000000..0cdf7d0 --- /dev/null +++ b/SelfSize/SelfSize/AppDelegate.h @@ -0,0 +1,41 @@ +// +// AppDelegate.h +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end + diff --git a/SelfSize/SelfSize/AppDelegate.m b/SelfSize/SelfSize/AppDelegate.m new file mode 100644 index 0000000..2b4b4fb --- /dev/null +++ b/SelfSize/SelfSize/AppDelegate.m @@ -0,0 +1,38 @@ +// +// AppDelegate.m +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "AppDelegate.h" + +@implementation AppDelegate + +@end diff --git a/SelfSize/SelfSize/Base.lproj/Main.storyboard b/SelfSize/SelfSize/Base.lproj/Main.storyboard new file mode 100644 index 0000000..03be3d6 --- /dev/null +++ b/SelfSize/SelfSize/Base.lproj/Main.storyboard @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SelfSize/SelfSize/Images.xcassets/AppIcon.appiconset/Contents.json b/SelfSize/SelfSize/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/SelfSize/SelfSize/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SelfSize/SelfSize/Images.xcassets/Contents.json b/SelfSize/SelfSize/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/SelfSize/SelfSize/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SelfSize/SelfSize/Info.plist b/SelfSize/SelfSize/Info.plist new file mode 100644 index 0000000..95c9575 --- /dev/null +++ b/SelfSize/SelfSize/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/SelfSize/SelfSize/LaunchScreen.storyboard b/SelfSize/SelfSize/LaunchScreen.storyboard new file mode 100644 index 0000000..883d763 --- /dev/null +++ b/SelfSize/SelfSize/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SelfSize/SelfSize/SourceData.plist b/SelfSize/SelfSize/SourceData.plist new file mode 100644 index 0000000..a824d0a --- /dev/null +++ b/SelfSize/SelfSize/SourceData.plist @@ -0,0 +1,2003 @@ + + + + + Chapter I + YOU don't know about me without you have read a book by the name of The Adventures of Tom Sawyer; but that ain't no matter. + That book was made by Mr. Mark Twain, and he told the truth, mainly. + There was things which he stretched, but mainly he told the truth. + That is nothing. + I never seen anybody but lied one time or another, without it was Aunt Polly, or the widow, or maybe Mary. + Aunt Polly—Tom's Aunt Polly, she is—and Mary, and the Widow Douglas is all told about in that book, which is mostly a true book, with some stretchers, as I said before. + Now the way that the book winds up is this: Tom and me found the money that the robbers hid in the cave, and it made us rich. + We got six thousand dollars apiece—all gold. + It was an awful sight of money when it was piled up. + Well, Judge Thatcher he took it and put it out at interest, and it fetched us a dollar a day apiece all the year round—more than a body could tell what to do with. + The Widow Douglas she took me for her son, and allowed she would sivilize me; but it was rough living in the house all the time, considering how dismal regular and decent the widow was in all her ways; and so when I couldn't stand it no longer I lit out. + I got into my old rags and my sugar-hogshead again, and was free and satisfied. + But Tom Sawyer he hunted me up and said he was going to start a band of robbers, and I might join if I would go back to the widow and be respectable. + So I went back. + The widow she cried over me, and called me a poor lost lamb, and she called me a lot of other names, too, but she never meant no harm by it. + She put me in them new clothes again, and I couldn't do nothing but sweat and sweat, and feel all cramped up. + Well, then, the old thing commenced again. + The widow rung a bell for supper, and you had to come to time. + When you got to the table you couldn't go right to eating, but you had to wait for the widow to tuck down her head and grumble a little over the victuals, though there warn't really anything the matter with them,—that is, nothing only everything was cooked by itself. + In a barrel of odds and ends it is different; things get mixed up, and the juice kind of swaps around, and the things go better. + After supper she got out her book and learned me about Moses and the Bulrushers, and I was in a sweat to find out all about him; but by and by she let it out that Moses had been dead a considerable long time; so then I didn't care no more about him, because I don't take no stock in dead people. + Pretty soon I wanted to smoke, and asked the widow to let me. + But she wouldn't. + She said it was a mean practice and wasn't clean, and I must try to not do it any more. + That is just the way with some people. + They get down on a thing when they don't know nothing about it. + Here she was a-bothering about Moses, which was no kin to her, and no use to anybody, being gone, you see, yet finding a power of fault with me for doing a thing that had some good in it. + And she took snuff, too; of course that was all right, because she done it herself. + Her sister, Miss Watson, a tolerable slim old maid, with goggles on, had just come to live with her, and took a set at me now with a spelling-book. + She worked me middling hard for about an hour, and then the widow made her ease up. + I couldn't stood it much longer. + Then for an hour it was deadly dull, and I was fidgety. + Miss Watson would say, "Don't put your feet up there, Huckleberry;" and "Don't scrunch up like that, Huckleberry—set up straight;" and pretty soon she would say, "Don't gap and stretch like that, Huckleberry—why don't you try to behave?" + Then she told me all about the bad place, and I said I wished I was there. + She got mad then, but I didn't mean no harm. + All I wanted was to go somewheres; all I wanted was a change, I warn't particular. + She said it was wicked to say what I said; said she wouldn't say it for the whole world; she was going to live so as to go to the good place. + Well, I couldn't see no advantage in going where she was going, so I made up my mind I wouldn't try for it. + But I never said so, because it would only make trouble, and wouldn't do no good. + Now she had got a start, and she went on and told me all about the good place. + She said all a body would have to do there was to go around all day long with a harp and sing, forever and ever. + So I didn't think much of it. + But I never said so. + I asked her if she reckoned Tom Sawyer would go there, and she said not by a considerable sight. + I was glad about that, because I wanted him and me to be together. + Miss Watson she kept pecking at me, and it got tiresome and lonesome. + By and by they fetched the niggers in and had prayers, and then everybody was off to bed. + I went up to my room with a piece of candle, and put it on the table. + Then I set down in a chair by the window and tried to think of something cheerful, but it warn't no use. + I felt so lonesome I most wished I was dead. + The stars were shining, and the leaves rustled in the woods ever so mournful; and I heard an owl, away off, who-whooing about somebody that was dead, and a whippowill and a dog crying about somebody that was going to die; and the wind was trying to whisper something to me, and I couldn't make out what it was, and so it made the cold shivers run over me. + Then away out in the woods I heard that kind of a sound that a ghost makes when it wants to tell about something that's on its mind and can't make itself understood, and so can't rest easy in its grave, and has to go about that way every night grieving. + I got so down-hearted and scared I did wish I had some company. + Pretty soon a spider went crawling up my shoulder, and I flipped it off and it lit in the candle; and before I could budge it was all shriveled up. + I didn't need anybody to tell me that that was an awful bad sign and would fetch me some bad luck, so I was scared and most shook the clothes off of me. + I got up and turned around in my tracks three times and crossed my breast every time; and then I tied up a little lock of my hair with a thread to keep witches away. + But I hadn't no confidence. + You do that when you've lost a horseshoe that you've found, instead of nailing it up over the door, but I hadn't ever heard anybody say it was any way to keep off bad luck when you'd killed a spider. + I set down again, a-shaking all over, and got out my pipe for a smoke; for the house was all as still as death now, and so the widow wouldn't know. + Well, after a long time I heard the clock away off in the town go boom—boom—boom—twelve licks; and all still again—stiller than ever. + Pretty soon I heard a twig snap down in the dark amongst the trees—something was a stirring. + I set still and listened. + Directly I could just barely hear a "me-yow! me-yow!" down there. + That was good! + Says I, "me-yow! me-yow!" as soft as I could, and then I put out the light and scrambled out of the window on to the shed. + Then I slipped down to the ground and crawled in among the trees, and, sure enough, there was Tom Sawyer waiting for me. + Chapter II + WE went tiptoeing along a path amongst the trees back towards the end of the widow's garden, stooping down so as the branches wouldn't scrape our heads. + When we was passing by the kitchen I fell over a root and made a noise. + We scrouched down and laid still. + Miss Watson's big nigger, named Jim, was setting in the kitchen door; we could see him pretty clear, because there was a light behind him. + He got up and stretched his neck out about a minute, listening. + Then he says: "Who dah?" + He listened some more; then he come tiptoeing down and stood right between us; we could a touched him, nearly. + Well, likely it was minutes and minutes that there warn't a sound, and we all there so close together. + There was a place on my ankle that got to itching, but I dasn't scratch it; and then my ear begun to itch; and next my back, right between my shoulders. + Seemed like I'd die if I couldn't scratch. + Well, I've noticed that thing plenty times since. + If you are with the quality, or at a funeral, or trying to go to sleep when you ain't sleepy—if you are anywheres where it won't do for you to scratch, why you will itch all over in upwards of a thousand places. + Pretty soon Jim says: + "Say, who is you? + Whar is you? + Dog my cats ef I didn' hear sumf'n. + Well, I know what I's gwyne to do: I's gwyne to set down here and listen tell I hears it agin." + So he set down on the ground betwixt me and Tom. + He leaned his back up against a tree, and stretched his legs out till one of them most touched one of mine. + My nose begun to itch. + It itched till the tears come into my eyes. + But I dasn't scratch. + Then it begun to itch on the inside. + Next I got to itching underneath. + I didn't know how I was going to set still. + This miserableness went on as much as six or seven minutes; but it seemed a sight longer than that. + I was itching in eleven different places now. + I reckoned I couldn't stand it more'n a minute longer, but I set my teeth hard and got ready to try. + Just then Jim begun to breathe heavy; next he begun to snore—and then I was pretty soon comfortable again. + Tom he made a sign to me—kind of a little noise with his mouth—and we went creeping away on our hands and knees. + When we was ten foot off Tom whispered to me, and wanted to tie Jim to the tree for fun. + But I said no; he might wake and make a disturbance, and then they'd find out I warn't in. + Then Tom said he hadn't got candles enough, and he would slip in the kitchen and get some more. + I didn't want him to try. + I said Jim might wake up and come. + But Tom wanted to resk it; so we slid in there and got three candles, and Tom laid five cents on the table for pay. + Then we got out, and I was in a sweat to get away; but nothing would do Tom but he must crawl to where Jim was, on his hands and knees, and play something on him. + I waited, and it seemed a good while, everything was so still and lonesome. + As soon as Tom was back we cut along the path, around the garden fence, and by and by fetched up on the steep top of the hill the other side of the house. + Tom said he slipped Jim's hat off of his head and hung it on a limb right over him, and Jim stirred a little, but he didn't wake. + Afterwards Jim said the witches be witched him and put him in a trance, and rode him all over the State, and then set him under the trees again, and hung his hat on a limb to show who done it. + And next time Jim told it he said they rode him down to New Orleans; and, after that, every time he told it he spread it more and more, till by and by he said they rode him all over the world, and tired him most to death, and his back was all over saddle-boils. + Jim was monstrous proud about it, and he got so he wouldn't hardly notice the other niggers. + Niggers would come miles to hear Jim tell about it, and he was more looked up to than any nigger in that country. + Strange niggers would stand with their mouths open and look him all over, same as if he was a wonder. + Niggers is always talking about witches in the dark by the kitchen fire; but whenever one was talking and letting on to know all about such things, Jim would happen in and say, "Hm! + What you know 'bout witches?" + and that nigger was corked up and had to take a back seat. + Jim always kept that five-center piece round his neck with a string, and said it was a charm the devil give to him with his own hands, and told him he could cure anybody with it and fetch witches whenever he wanted to just by saying something to it; but he never told what it was he said to it. + Niggers would come from all around there and give Jim anything they had, just for a sight of that five-center piece; but they wouldn't touch it, because the devil had had his hands on it. + Jim was most ruined for a servant, because he got stuck up on account of having seen the devil and been rode by witches. + Well, when Tom and me got to the edge of the hilltop we looked away down into the village and could see three or four lights twinkling, where there was sick folks, maybe; and the stars over us was sparkling ever so fine; and down by the village was the river, a whole mile broad, and awful still and grand. + We went down the hill and found Jo Harper and Ben Rogers, and two or three more of the boys, hid in the old tanyard. + So we unhitched a skiff and pulled down the river two mile and a half, to the big scar on the hillside, and went ashore. + We went to a clump of bushes, and Tom made everybody swear to keep the secret, and then showed them a hole in the hill, right in the thickest part of the bushes. + Then we lit the candles, and crawled in on our hands and knees. + We went about two hundred yards, and then the cave opened up. + Tom poked about amongst the passages, and pretty soon ducked under a wall where you wouldn't a noticed that there was a hole. + We went along a narrow place and got into a kind of room, all damp and sweaty and cold, and there we stopped. + Tom says: + "Now, we'll start this band of robbers and call it Tom Sawyer's Gang. + Everybody that wants to join has got to take an oath, and write his name in blood." + Everybody was willing. + So Tom got out a sheet of paper that he had wrote the oath on, and read it. + It swore every boy to stick to the band, and never tell any of the secrets; and if anybody done anything to any boy in the band, whichever boy was ordered to kill that person and his family must do it, and he mustn't eat and he mustn't sleep till he had killed them and hacked a cross in their breasts, which was the sign of the band. + And nobody that didn't belong to the band could use that mark, and if he did he must be sued; and if he done it again he must be killed. + And if anybody that belonged to the band told the secrets, he must have his throat cut, and then have his carcass burnt up and the ashes scattered all around, and his name blotted off of the list with blood and never mentioned again by the gang, but have a curse put on it and be forgot forever. + Everybody said it was a real beautiful oath, and asked Tom if he got it out of his own head. + He said, some of it, but the rest was out of pirate-books and robber-books, and every gang that was high-toned had it. + Some thought it would be good to kill the _families_ of boys that told the secrets. + Tom said it was a good idea, so he took a pencil and wrote it in. + Then Ben Rogers says: + "Here's Huck Finn, he hain't got no family; what you going to do 'bout him?" + "Well, hain't he got a father?" + says Tom Sawyer. + "Yes, he's got a father, but you can't never find him these days. + He used to lay drunk with the hogs in the tanyard, but he hain't been seen in these parts for a year or more." + They talked it over, and they was going to rule me out, because they said every boy must have a family or somebody to kill, or else it wouldn't be fair and square for the others. + Well, nobody could think of anything to do—everybody was stumped, and set still. + I was most ready to cry; but all at once I thought of a way, and so I offered them Miss Watson—they could kill her. + Everybody said: + "Oh, she'll do. + That's all right. + Huck can come in." + Then they all stuck a pin in their fingers to get blood to sign with, and I made my mark on the paper. + "Now," says Ben Rogers, "what's the line of business of this Gang?" + "Nothing only robbery and murder," Tom said. + "But who are we going to rob? + —houses, or cattle, or—" + "Stuff! + stealing cattle and such things ain't robbery; it's burglary," says Tom Sawyer. + "We ain't burglars. + That ain't no sort of style. + We are highwaymen. + We stop stages and carriages on the road, with masks on, and kill the people and take their watches and money." + "Must we always kill the people?" + "Oh, certainly. + It's best. + Some authorities think different, but mostly it's considered best to kill them—except some that you bring to the cave here, and keep them till they're ransomed." + "Ransomed? + What's that?" + "I don't know. + But that's what they do. + I've seen it in books; and so of course that's what we've got to do." + "But how can we do it if we don't know what it is?" + "Why, blame it all, we've _got_ to do it. + Don't I tell you it's in the books? + Do you want to go to doing different from what's in the books, and get things all muddled up?" + "Oh, that's all very fine to _say_, Tom Sawyer, but how in the nation are these fellows going to be ransomed if we don't know how to do it to them? + —that's the thing I want to get at. + Now, what do you reckon it is?" + "Well, I don't know. + But per'aps if we keep them till they're ransomed, it means that we keep them till they're dead." + "Now, that's something _like_. + That'll answer. + Why couldn't you said that before? + We'll keep them till they're ransomed to death; and a bothersome lot they'll be, too—eating up everything, and always trying to get loose." + "How you talk, Ben Rogers. + How can they get loose when there's a guard over them, ready to shoot them down if they move a peg?" + "A guard! + Well, that _is_ good. + So somebody's got to set up all night and never get any sleep, just so as to watch them. + I think that's foolishness. + Why can't a body take a club and ransom them as soon as they get here?" + "Because it ain't in the books so—that's why. + Now, Ben Rogers, do you want to do things regular, or don't you? + —that's the idea. + Don't you reckon that the people that made the books knows what's the correct thing to do? + Do you reckon _you_ can learn 'em anything? + Not by a good deal. + No, sir, we'll just go on and ransom them in the regular way." + "All right. + I don't mind; but I say it's a fool way, anyhow. + Say, do we kill the women, too?" + "Well, Ben Rogers, if I was as ignorant as you I wouldn't let on. + Kill the women? + No; nobody ever saw anything in the books like that. + You fetch them to the cave, and you're always as polite as pie to them; and by and by they fall in love with you, and never want to go home any more." + "Well, if that's the way I'm agreed, but I don't take no stock in it. + Mighty soon we'll have the cave so cluttered up with women, and fellows waiting to be ransomed, that there won't be no place for the robbers. + But go ahead, I ain't got nothing to say." + Little Tommy Barnes was asleep now, and when they waked him up he was scared, and cried, and said he wanted to go home to his ma, and didn't want to be a robber any more. + So they all made fun of him, and called him cry-baby, and that made him mad, and he said he would go straight and tell all the secrets. + But Tom give him five cents to keep quiet, and said we would all go home and meet next week, and rob somebody and kill some people. + Ben Rogers said he couldn't get out much, only Sundays, and so he wanted to begin next Sunday; but all the boys said it would be wicked to do it on Sunday, and that settled the thing. + They agreed to get together and fix a day as soon as they could, and then we elected Tom Sawyer first captain and Jo Harper second captain of the Gang, and so started home. + I clumb up the shed and crept into my window just before day was breaking. + My new clothes was all greased up and clayey, and I was dog-tired. + CHAPTER III. + WELL, I got a good going-over in the morning from old Miss Watson on account of my clothes; but the widow she didn't scold, but only cleaned off the grease and clay, and looked so sorry that I thought I would behave awhile if I could. + Then Miss Watson she took me in the closet and prayed, but nothing come of it. + She told me to pray every day, and whatever I asked for I would get it. + But it warn't so. + I tried it. + Once I got a fish-line, but no hooks. + It warn't any good to me without hooks. + I tried for the hooks three or four times, but somehow I couldn't make it work. + By and by, one day, I asked Miss Watson to try for me, but she said I was a fool. + She never told me why, and I couldn't make it out no way. + I set down one time back in the woods, and had a long think about it. + I says to myself, if a body can get anything they pray for, why don't Deacon Winn get back the money he lost on pork? + Why can't the widow get back her silver snuffbox that was stole? + Why can't Miss Watson fat up? + No, says I to my self, there ain't nothing in it. + I went and told the widow about it, and she said the thing a body could get by praying for it was "spiritual gifts." + This was too many for me, but she told me what she meant—I must help other people, and do everything I could for other people, and look out for them all the time, and never think about myself. + This was including Miss Watson, as I took it. + I went out in the woods and turned it over in my mind a long time, but I couldn't see no advantage about it—except for the other people; so at last I reckoned I wouldn't worry about it any more, but just let it go. + Sometimes the widow would take me one side and talk about Providence in a way to make a body's mouth water; but maybe next day Miss Watson would take hold and knock it all down again. + I judged I could see that there was two Providences, and a poor chap would stand considerable show with the widow's Providence, but if Miss Watson's got him there warn't no help for him any more. + I thought it all out, and reckoned I would belong to the widow's if he wanted me, though I couldn't make out how he was a-going to be any better off then than what he was before, seeing I was so ignorant, and so kind of low-down and ornery. + Pap he hadn't been seen for more than a year, and that was comfortable for me; I didn't want to see him no more. + He used to always whale me when he was sober and could get his hands on me; though I used to take to the woods most of the time when he was around. + Well, about this time he was found in the river drownded, about twelve mile above town, so people said. + They judged it was him, anyway; said this drownded man was just his size, and was ragged, and had uncommon long hair, which was all like pap; but they couldn't make nothing out of the face, because it had been in the water so long it warn't much like a face at all. + They said he was floating on his back in the water. + They took him and buried him on the bank. + But I warn't comfortable long, because I happened to think of something. + I knowed mighty well that a drownded man don't float on his back, but on his face. + So I knowed, then, that this warn't pap, but a woman dressed up in a man's clothes. + So I was uncomfortable again. + I judged the old man would turn up again by and by, though I wished he wouldn't. + We played robber now and then about a month, and then I resigned. + All the boys did. + We hadn't robbed nobody, hadn't killed any people, but only just pretended. + We used to hop out of the woods and go charging down on hog-drivers and women in carts taking garden stuff to market, but we never hived any of them. + Tom Sawyer called the hogs "ingots," and he called the turnips and stuff "julery," and we would go to the cave and powwow over what we had done, and how many people we had killed and marked. + But I couldn't see no profit in it. + One time Tom sent a boy to run about town with a blazing stick, which he called a slogan (which was the sign for the Gang to get together), and then he said he had got secret news by his spies that next day a whole parcel of Spanish merchants and rich A-rabs was going to camp in Cave Hollow with two hundred elephants, and six hundred camels, and over a thousand "sumter" mules, all loaded down with di'monds, and they didn't have only a guard of four hundred soldiers, and so we would lay in ambuscade, as he called it, and kill the lot and scoop the things. + He said we must slick up our swords and guns, and get ready. + He never could go after even a turnip-cart but he must have the swords and guns all scoured up for it, though they was only lath and broomsticks, and you might scour at them till you rotted, and then they warn't worth a mouthful of ashes more than what they was before. + I didn't believe we could lick such a crowd of Spaniards and A-rabs, but I wanted to see the camels and elephants, so I was on hand next day, Saturday, in the ambuscade; and when we got the word we rushed out of the woods and down the hill. + But there warn't no Spaniards and A-rabs, and there warn't no camels nor no elephants. + It warn't anything but a Sunday-school picnic, and only a primer-class at that. + We busted it up, and chased the children up the hollow; but we never got anything but some doughnuts and jam, though Ben Rogers got a rag doll, and Jo Harper got a hymn-book and a tract; and then the teacher charged in, and made us drop everything and cut. + I didn't see no di'monds, and I told Tom Sawyer so. + He said there was loads of them there, anyway; and he said there was A-rabs there, too, and elephants and things. + I said, why couldn't we see them, then? + He said if I warn't so ignorant, but had read a book called Don Quixote, I would know without asking. + He said it was all done by enchantment. + He said there was hundreds of soldiers there, and elephants and treasure, and so on, but we had enemies which he called magicians; and they had turned the whole thing into an infant Sunday-school, just out of spite. + I said, all right; then the thing for us to do was to go for the magicians. + Tom Sawyer said I was a numskull. + "Why," said he, "a magician could call up a lot of genies, and they would hash you up like nothing before you could say Jack Robinson. + They are as tall as a tree and as big around as a church." + "Well," I says, "s'pose we got some genies to help _us_—can't we lick the other crowd then?" + "How you going to get them?" + "I don't know. + How do _they_ get them?" + "Why, they rub an old tin lamp or an iron ring, and then the genies come tearing in, with the thunder and lightning a-ripping around and the smoke a-rolling, and everything they're told to do they up and do it. + They don't think nothing of pulling a shot-tower up by the roots, and belting a Sunday-school superintendent over the head with it—or any other man." + "Who makes them tear around so?" + "Why, whoever rubs the lamp or the ring. + They belong to whoever rubs the lamp or the ring, and they've got to do whatever he says. + If he tells them to build a palace forty miles long out of di'monds, and fill it full of chewing-gum, or whatever you want, and fetch an emperor's daughter from China for you to marry, they've got to do it—and they've got to do it before sun-up next morning, too. + And more: they've got to waltz that palace around over the country wherever you want it, you understand." + "Well," says I, "I think they are a pack of flat-heads for not keeping the palace themselves 'stead of fooling them away like that. + And what's more—if I was one of them I would see a man in Jericho before I would drop my business and come to him for the rubbing of an old tin lamp." + "How you talk, Huck Finn. + Why, you'd _have_ to come when he rubbed it, whether you wanted to or not." + "What! + and I as high as a tree and as big as a church? + All right, then; I _would_ come; but I lay I'd make that man climb the highest tree there was in the country." + "Shucks, it ain't no use to talk to you, Huck Finn. + You don't seem to know anything, somehow—perfect saphead." + I thought all this over for two or three days, and then I reckoned I would see if there was anything in it. + I got an old tin lamp and an iron ring, and went out in the woods and rubbed and rubbed till I sweat like an Injun, calculating to build a palace and sell it; but it warn't no use, none of the genies come. + So then I judged that all that stuff was only just one of Tom Sawyer's lies. + I reckoned he believed in the A-rabs and the elephants, but as for me I think different. + It had all the marks of a Sunday-school. + CHAPTER IV. + WELL, three or four months run along, and it was well into the winter now. + I had been to school most all the time and could spell and read and write just a little, and could say the multiplication table up to six times seven is thirty-five, and I don't reckon I could ever get any further than that if I was to live forever. + I don't take no stock in mathematics, anyway. + At first I hated the school, but by and by I got so I could stand it. + Whenever I got uncommon tired I played hookey, and the hiding I got next day done me good and cheered me up. + So the longer I went to school the easier it got to be. + I was getting sort of used to the widow's ways, too, and they warn't so raspy on me. + Living in a house and sleeping in a bed pulled on me pretty tight mostly, but before the cold weather I used to slide out and sleep in the woods sometimes, and so that was a rest to me. + I liked the old ways best, but I was getting so I liked the new ones, too, a little bit. + The widow said I was coming along slow but sure, and doing very satisfactory. + She said she warn't ashamed of me. + One morning I happened to turn over the salt-cellar at breakfast. + I reached for some of it as quick as I could to throw over my left shoulder and keep off the bad luck, but Miss Watson was in ahead of me, and crossed me off. + She says, "Take your hands away, Huckleberry; what a mess you are always making!" + The widow put in a good word for me, but that warn't going to keep off the bad luck, I knowed that well enough. + I started out, after breakfast, feeling worried and shaky, and wondering where it was going to fall on me, and what it was going to be. + There is ways to keep off some kinds of bad luck, but this wasn't one of them kind; so I never tried to do anything, but just poked along low-spirited and on the watch-out. + I went down to the front garden and clumb over the stile where you go through the high board fence. + There was an inch of new snow on the ground, and I seen somebody's tracks. + They had come up from the quarry and stood around the stile a while, and then went on around the garden fence. + It was funny they hadn't come in, after standing around so. + I couldn't make it out. + It was very curious, somehow. + I was going to follow around, but I stooped down to look at the tracks first. + I didn't notice anything at first, but next I did. + There was a cross in the left boot-heel made with big nails, to keep off the devil. + I was up in a second and shinning down the hill. + I looked over my shoulder every now and then, but I didn't see nobody. + I was at Judge Thatcher's as quick as I could get there. + He said: + "Why, my boy, you are all out of breath. + Did you come for your interest?" + "No, sir," I says; "is there some for me?" + "Oh, yes, a half-yearly is in last night—over a hundred and fifty dollars. + Quite a fortune for you. + You had better let me invest it along with your six thousand, because if you take it you'll spend it." + "No, sir," I says, "I don't want to spend it. + I don't want it at all—nor the six thousand, nuther. + I want you to take it; I want to give it to you—the six thousand and all." + He looked surprised. + He couldn't seem to make it out. + He says: + "Why, what can you mean, my boy?" + I says, "Don't you ask me no questions about it, please. + You'll take it—won't you?" + He says: + "Well, I'm puzzled. + Is something the matter?" + "Please take it," says I, "and don't ask me nothing—then I won't have to tell no lies." + He studied a while, and then he says: + "Oho-o! + I think I see. + You want to _sell_ all your property to me—not give it. + That's the correct idea." + Then he wrote something on a paper and read it over, and says: + "There; you see it says 'for a consideration.' + That means I have bought it of you and paid you for it. + Here's a dollar for you. + Now you sign it." + So I signed it, and left. + Miss Watson's nigger, Jim, had a hair-ball as big as your fist, which had been took out of the fourth stomach of an ox, and he used to do magic with it. + He said there was a spirit inside of it, and it knowed everything. + So I went to him that night and told him pap was here again, for I found his tracks in the snow. + What I wanted to know was, what he was going to do, and was he going to stay? + Jim got out his hair-ball and said something over it, and then he held it up and dropped it on the floor. + It fell pretty solid, and only rolled about an inch. + Jim tried it again, and then another time, and it acted just the same. + Jim got down on his knees, and put his ear against it and listened. + But it warn't no use; he said it wouldn't talk. + He said sometimes it wouldn't talk without money. + I told him I had an old slick counterfeit quarter that warn't no good because the brass showed through the silver a little, and it wouldn't pass nohow, even if the brass didn't show, because it was so slick it felt greasy, and so that would tell on it every time. + (I reckoned I wouldn't say nothing about the dollar I got from the judge.) + I said it was pretty bad money, but maybe the hair-ball would take it, because maybe it wouldn't know the difference. + Jim smelt it and bit it and rubbed it, and said he would manage so the hair-ball would think it was good. + He said he would split open a raw Irish potato and stick the quarter in between and keep it there all night, and next morning you couldn't see no brass, and it wouldn't feel greasy no more, and so anybody in town would take it in a minute, let alone a hair-ball. + Well, I knowed a potato would do that before, but I had forgot it. + Jim put the quarter under the hair-ball, and got down and listened again. + This time he said the hair-ball was all right. + He said it would tell my whole fortune if I wanted it to. + I says, go on. + So the hair-ball talked to Jim, and Jim told it to me. + He says: + "Yo' ole father doan' know yit what he's a-gwyne to do. + Sometimes he spec he'll go 'way, en den agin he spec he'll stay. + De bes' way is to res' easy en let de ole man take his own way. + Dey's two angels hoverin' roun' 'bout him. + One uv 'em is white en shiny, en t'other one is black. + De white one gits him to go right a little while, den de black one sail in en bust it all up. + A body can't tell yit which one gwyne to fetch him at de las'. + But you is all right. + You gwyne to have considable trouble in yo' life, en considable joy. + Sometimes you gwyne to git hurt, en sometimes you gwyne to git sick; but every time you's gwyne to git well agin. + Dey's two gals flyin' 'bout you in yo' life. + One uv 'em's light en t'other one is dark. + One is rich en t'other is po'. + You's gwyne to marry de po' one fust en de rich one by en by. + You wants to keep 'way fum de water as much as you kin, en don't run no resk, 'kase it's down in de bills dat you's gwyne to git hung." + When I lit my candle and went up to my room that night there sat pap his own self! + CHAPTER V. + I had shut the door to. + Then I turned around and there he was. + I used to be scared of him all the time, he tanned me so much. + I reckoned I was scared now, too; but in a minute I see I was mistaken—that is, after the first jolt, as you may say, when my breath sort of hitched, he being so unexpected; but right away after I see I warn't scared of him worth bothring about. + He was most fifty, and he looked it. + His hair was long and tangled and greasy, and hung down, and you could see his eyes shining through like he was behind vines. + It was all black, no gray; so was his long, mixed-up whiskers. + There warn't no color in his face, where his face showed; it was white; not like another man's white, but a white to make a body sick, a white to make a body's flesh crawl—a tree-toad white, a fish-belly white. + As for his clothes—just rags, that was all. + He had one ankle resting on t'other knee; the boot on that foot was busted, and two of his toes stuck through, and he worked them now and then. + His hat was laying on the floor—an old black slouch with the top caved in, like a lid. + I stood a-looking at him; he set there a-looking at me, with his chair tilted back a little. + I set the candle down. + I noticed the window was up; so he had clumb in by the shed. + He kept a-looking me all over. + By and by he says: "Starchy clothes—very. + You think you're a good deal of a big-bug, _don't_ you?" + "Maybe I am, maybe I ain't," I says. + "Don't you give me none o' your lip," says he. + "You've put on considerable many frills since I been away. + I'll take you down a peg before I get done with you. + You're educated, too, they say—can read and write. + You think you're better'n your father, now, don't you, because he can't? + _I'll_ take it out of you. + Who told you you might meddle with such hifalut'n foolishness, hey? + —who told you you could?" + "The widow. + She told me." + "The widow, hey? + —and who told the widow she could put in her shovel about a thing that ain't none of her business?" + "Nobody never told her." + "Well, I'll learn her how to meddle. + And looky here—you drop that school, you hear? + I'll learn people to bring up a boy to put on airs over his own father and let on to be better'n what _he_ is. + You lemme catch you fooling around that school again, you hear? + Your mother couldn't read, and she couldn't write, nuther, before she died. + None of the family couldn't before _they_ died. + I can't; and here you're a-swelling yourself up like this. + I ain't the man to stand it—you hear? + Say, lemme hear you read." + I took up a book and begun something about General Washington and the wars. + When I'd read about a half a minute, he fetched the book a whack with his hand and knocked it across the house. + He says: "It's so. + You can do it. + I had my doubts when you told me. + Now looky here; you stop that putting on frills. + I won't have it. + I'll lay for you, my smarty; and if I catch you about that school I'll tan you good. + First you know you'll get religion, too. + I never see such a son." + He took up a little blue and yaller picture of some cows and a boy, and says: "What's this?" + "It's something they give me for learning my lessons good." + He tore it up, and says: "I'll give you something better—I'll give you a cowhide." + He set there a-mumbling and a-growling a minute, and then he says: "_Ain't_ you a sweet-scented dandy, though? + A bed; and bedclothes; and a look'n'-glass; and a piece of carpet on the floor—and your own father got to sleep with the hogs in the tanyard. + I never see such a son. + I bet I'll take some o' these frills out o' you before I'm done with you. + Why, there ain't no end to your airs—they say you're rich. + Hey? + —how's that?" + "They lie—that's how." + "Looky here—mind how you talk to me; I'm a-standing about all I can stand now—so don't gimme no sass. + I've been in town two days, and I hain't heard nothing but about you bein' rich. + I heard about it away down the river, too. + That's why I come. + You git me that money to-morrow—I want it." + "I hain't got no money." + "It's a lie. + Judge Thatcher's got it. + You git it. + I want it." + "I hain't got no money, I tell you. + You ask Judge Thatcher; he'll tell you the same." + "All right. + I'll ask him; and I'll make him pungle, too, or I'll know the reason why. + Say, how much you got in your pocket? + I want it." + "I hain't got only a dollar, and I want that to—" "It don't make no difference what you want it for—you just shell it out." + He took it and bit it to see if it was good, and then he said he was going down town to get some whisky; said he hadn't had a drink all day. + When he had got out on the shed he put his head in again, and cussed me for putting on frills and trying to be better than him; and when I reckoned he was gone he come back and put his head in again, and told me to mind about that school, because he was going to lay for me and lick me if I didn't drop that. + Next day he was drunk, and he went to Judge Thatcher's and bullyragged him, and tried to make him give up the money; but he couldn't, and then he swore he'd make the law force him. + The judge and the widow went to law to get the court to take me away from him and let one of them be my guardian; but it was a new judge that had just come, and he didn't know the old man; so he said courts mustn't interfere and separate families if they could help it; said he'd druther not take a child away from its father. + So Judge Thatcher and the widow had to quit on the business. + That pleased the old man till he couldn't rest. + He said he'd cowhide me till I was black and blue if I didn't raise some money for him. + I borrowed three dollars from Judge Thatcher, and pap took it and got drunk, and went a-blowing around and cussing and whooping and carrying on; and he kept it up all over town, with a tin pan, till most midnight; then they jailed him, and next day they had him before court, and jailed him again for a week. + But he said _he_ was satisfied; said he was boss of his son, and he'd make it warm for _him_. + When he got out the new judge said he was a-going to make a man of him. + So he took him to his own house, and dressed him up clean and nice, and had him to breakfast and dinner and supper with the family, and was just old pie to him, so to speak. + And after supper he talked to him about temperance and such things till the old man cried, and said he'd been a fool, and fooled away his life; but now he was a-going to turn over a new leaf and be a man nobody wouldn't be ashamed of, and he hoped the judge would help him and not look down on him. + The judge said he could hug him for them words; so he cried, and his wife she cried again; pap said he'd been a man that had always been misunderstood before, and the judge said he believed it. + The old man said that what a man wanted that was down was sympathy, and the judge said it was so; so they cried again. + And when it was bedtime the old man rose up and held out his hand, and says: "Look at it, gentlemen and ladies all; take a-hold of it; shake it. + There's a hand that was the hand of a hog; but it ain't so no more; it's the hand of a man that's started in on a new life, and'll die before he'll go back. + You mark them words—don't forget I said them. + It's a clean hand now; shake it—don't be afeard." + So they shook it, one after the other, all around, and cried. + The judge's wife she kissed it. + Then the old man he signed a pledge—made his mark. + The judge said it was the holiest time on record, or something like that. + Then they tucked the old man into a beautiful room, which was the spare room, and in the night some time he got powerful thirsty and clumb out on to the porch-roof and slid down a stanchion and traded his new coat for a jug of forty-rod, and clumb back again and had a good old time; and towards daylight he crawled out again, drunk as a fiddler, and rolled off the porch and broke his left arm in two places, and was most froze to death when somebody found him after sun-up. + And when they come to look at that spare room they had to take soundings before they could navigate it. + The judge he felt kind of sore. + He said he reckoned a body could reform the old man with a shotgun, maybe, but he didn't know no other way. + CHAPTER VI. + WELL, pretty soon the old man was up and around again, and then he went for Judge Thatcher in the courts to make him give up that money, and he went for me, too, for not stopping school. + He catched me a couple of times and thrashed me, but I went to school just the same, and dodged him or outrun him most of the time. + I didn't want to go to school much before, but I reckoned I'd go now to spite pap. + That law trial was a slow business—appeared like they warn't ever going to get started on it; so every now and then I'd borrow two or three dollars off of the judge for him, to keep from getting a cowhiding. + Every time he got money he got drunk; and every time he got drunk he raised Cain around town; and every time he raised Cain he got jailed. + He was just suited—this kind of thing was right in his line. + He got to hanging around the widow's too much and so she told him at last that if he didn't quit using around there she would make trouble for him. + Well, _wasn't_ he mad? + He said he would show who was Huck Finn's boss. + So he watched out for me one day in the spring, and catched me, and took me up the river about three mile in a skiff, and crossed over to the Illinois shore where it was woody and there warn't no houses but an old log hut in a place where the timber was so thick you couldn't find it if you didn't know where it was. + He kept me with him all the time, and I never got a chance to run off. + We lived in that old cabin, and he always locked the door and put the key under his head nights. + He had a gun which he had stole, I reckon, and we fished and hunted, and that was what we lived on. + Every little while he locked me in and went down to the store, three miles, to the ferry, and traded fish and game for whisky, and fetched it home and got drunk and had a good time, and licked me. + The widow she found out where I was by and by, and she sent a man over to try to get hold of me; but pap drove him off with the gun, and it warn't long after that till I was used to being where I was, and liked it—all but the cowhide part. + It was kind of lazy and jolly, laying off comfortable all day, smoking and fishing, and no books nor study. + Two months or more run along, and my clothes got to be all rags and dirt, and I didn't see how I'd ever got to like it so well at the widow's, where you had to wash, and eat on a plate, and comb up, and go to bed and get up regular, and be forever bothering over a book, and have old Miss Watson pecking at you all the time. + I didn't want to go back no more. + I had stopped cussing, because the widow didn't like it; but now I took to it again because pap hadn't no objections. + It was pretty good times up in the woods there, take it all around. + But by and by pap got too handy with his hick'ry, and I couldn't stand it. + I was all over welts. + He got to going away so much, too, and locking me in. + Once he locked me in and was gone three days. + It was dreadful lonesome. + I judged he had got drownded, and I wasn't ever going to get out any more. + I was scared. + I made up my mind I would fix up some way to leave there. + I had tried to get out of that cabin many a time, but I couldn't find no way. + There warn't a window to it big enough for a dog to get through. + I couldn't get up the chimbly; it was too narrow. + The door was thick, solid oak slabs. + Pap was pretty careful not to leave a knife or anything in the cabin when he was away; I reckon I had hunted the place over as much as a hundred times; well, I was most all the time at it, because it was about the only way to put in the time. + But this time I found something at last; I found an old rusty wood-saw without any handle; it was laid in between a rafter and the clapboards of the roof. + I greased it up and went to work. + There was an old horse-blanket nailed against the logs at the far end of the cabin behind the table, to keep the wind from blowing through the chinks and putting the candle out. + I got under the table and raised the blanket, and went to work to saw a section of the big bottom log out—big enough to let me through. + Well, it was a good long job, but I was getting towards the end of it when I heard pap's gun in the woods. + I got rid of the signs of my work, and dropped the blanket and hid my saw, and pretty soon pap come in. + Pap warn't in a good humor—so he was his natural self. + He said he was down town, and everything was going wrong. + His lawyer said he reckoned he would win his lawsuit and get the money if they ever got started on the trial; but then there was ways to put it off a long time, and Judge Thatcher knowed how to do it. + And he said people allowed there'd be another trial to get me away from him and give me to the widow for my guardian, and they guessed it would win this time. + This shook me up considerable, because I didn't want to go back to the widow's any more and be so cramped up and sivilized, as they called it. + Then the old man got to cussing, and cussed everything and everybody he could think of, and then cussed them all over again to make sure he hadn't skipped any, and after that he polished off with a kind of a general cuss all round, including a considerable parcel of people which he didn't know the names of, and so called them what's-his-name when he got to them, and went right along with his cussing. + He said he would like to see the widow get me. + He said he would watch out, and if they tried to come any such game on him he knowed of a place six or seven mile off to stow me in, where they might hunt till they dropped and they couldn't find me. + That made me pretty uneasy again, but only for a minute; I reckoned I wouldn't stay on hand till he got that chance. + The old man made me go to the skiff and fetch the things he had got. + There was a fifty-pound sack of corn meal, and a side of bacon, ammunition, and a four-gallon jug of whisky, and an old book and two newspapers for wadding, besides some tow. + I toted up a load, and went back and set down on the bow of the skiff to rest. + I thought it all over, and I reckoned I would walk off with the gun and some lines, and take to the woods when I run away. + I guessed I wouldn't stay in one place, but just tramp right across the country, mostly night times, and hunt and fish to keep alive, and so get so far away that the old man nor the widow couldn't ever find me any more. + I judged I would saw out and leave that night if pap got drunk enough, and I reckoned he would. + I got so full of it I didn't notice how long I was staying till the old man hollered and asked me whether I was asleep or drownded. + I got the things all up to the cabin, and then it was about dark. + While I was cooking supper the old man took a swig or two and got sort of warmed up, and went to ripping again. + He had been drunk over in town, and laid in the gutter all night, and he was a sight to look at. + A body would a thought he was Adam—he was just all mud. + Whenever his liquor begun to work he most always went for the govment, this time he says: + "Call this a govment! + why, just look at it and see what it's like. + Here's the law a-standing ready to take a man's son away from him—a man's own son, which he has had all the trouble and all the anxiety and all the expense of raising. + Yes, just as that man has got that son raised at last, and ready to go to work and begin to do suthin' for _him_ and give him a rest, the law up and goes for him. + And they call _that_ govment! + That ain't all, nuther. + The law backs that old Judge Thatcher up and helps him to keep me out o' my property. + Here's what the law does: The law takes a man worth six thousand dollars and up'ards, and jams him into an old trap of a cabin like this, and lets him go round in clothes that ain't fitten for a hog. + They call that govment! + A man can't get his rights in a govment like this. + Sometimes I've a mighty notion to just leave the country for good and all. + Yes, and I _told_ 'em so; I told old Thatcher so to his face. + Lots of 'em heard me, and can tell what I said. + Says I, for two cents I'd leave the blamed country and never come a-near it agin. + Them's the very words. + I says look at my hat—if you call it a hat—but the lid raises up and the rest of it goes down till it's below my chin, and then it ain't rightly a hat at all, but more like my head was shoved up through a jint o' stove-pipe. + Look at it, says I—such a hat for me to wear—one of the wealthiest men in this town if I could git my rights. + "Oh, yes, this is a wonderful govment, wonderful. + Why, looky here. + There was a free nigger there from Ohio—a mulatter, most as white as a white man. + He had the whitest shirt on you ever see, too, and the shiniest hat; and there ain't a man in that town that's got as fine clothes as what he had; and he had a gold watch and chain, and a silver-headed cane—the awfulest old gray-headed nabob in the State. + And what do you think? + They said he was a p'fessor in a college, and could talk all kinds of languages, and knowed everything. + And that ain't the wust. + They said he could _vote_ when he was at home. + Well, that let me out. + Thinks I, what is the country a-coming to? + It was 'lection day, and I was just about to go and vote myself if I warn't too drunk to get there; but when they told me there was a State in this country where they'd let that nigger vote, I drawed out. + I says I'll never vote agin. + Them's the very words I said; they all heard me; and the country may rot for all me—I'll never vote agin as long as I live. + And to see the cool way of that nigger—why, he wouldn't a give me the road if I hadn't shoved him out o' the way. + I says to the people, why ain't this nigger put up at auction and sold? + —that's what I want to know. + And what do you reckon they said? + Why, they said he couldn't be sold till he'd been in the State six months, and he hadn't been there that long yet. + There, now—that's a specimen. + They call that a govment that can't sell a free nigger till he's been in the State six months. + Here's a govment that calls itself a govment, and lets on to be a govment, and thinks it is a govment, and yet's got to set stock-still for six whole months before it can take a hold of a prowling, thieving, infernal, white-shirted free nigger, and—" + Pap was agoing on so he never noticed where his old limber legs was taking him to, so he went head over heels over the tub of salt pork and barked both shins, and the rest of his speech was all the hottest kind of language—mostly hove at the nigger and the govment, though he give the tub some, too, all along, here and there. + He hopped around the cabin considerable, first on one leg and then on the other, holding first one shin and then the other one, and at last he let out with his left foot all of a sudden and fetched the tub a rattling kick. + But it warn't good judgment, because that was the boot that had a couple of his toes leaking out of the front end of it; so now he raised a howl that fairly made a body's hair raise, and down he went in the dirt, and rolled there, and held his toes; and the cussing he done then laid over anything he had ever done previous. + He said so his own self afterwards. + He had heard old Sowberry Hagan in his best days, and he said it laid over him, too; but I reckon that was sort of piling it on, maybe. + After supper pap took the jug, and said he had enough whisky there for two drunks and one delirium tremens. + That was always his word. + I judged he would be blind drunk in about an hour, and then I would steal the key, or saw myself out, one or t'other. + He drank and drank, and tumbled down on his blankets by and by; but luck didn't run my way. + He didn't go sound asleep, but was uneasy. + He groaned and moaned and thrashed around this way and that for a long time. + At last I got so sleepy I couldn't keep my eyes open all I could do, and so before I knowed what I was about I was sound asleep, and the candle burning. + I don't know how long I was asleep, but all of a sudden there was an awful scream and I was up. + There was pap looking wild, and skipping around every which way and yelling about snakes. + He said they was crawling up his legs; and then he would give a jump and scream, and say one had bit him on the cheek—but I couldn't see no snakes. + He started and run round and round the cabin, hollering "Take him off! + take him off! + he's biting me on the neck!" + I never see a man look so wild in the eyes. + Pretty soon he was all fagged out, and fell down panting; then he rolled over and over wonderful fast, kicking things every which way, and striking and grabbing at the air with his hands, and screaming and saying there was devils a-hold of him. + He wore out by and by, and laid still a while, moaning. + Then he laid stiller, and didn't make a sound. + I could hear the owls and the wolves away off in the woods, and it seemed terrible still. + He was laying over by the corner. + By and by he raised up part way and listened, with his head to one side. + He says, very low: + "Tramp—tramp—tramp; that's the dead; tramp—tramp—tramp; they're coming after me; but I won't go. + Oh, they're here! + don't touch me—don't! + hands off—they're cold; let go. + Oh, let a poor devil alone!" + Then he went down on all fours and crawled off, begging them to let him alone, and he rolled himself up in his blanket and wallowed in under the old pine table, still a-begging; and then he went to crying. + I could hear him through the blanket. + By and by he rolled out and jumped up on his feet looking wild, and he see me and went for me. + He chased me round and round the place with a clasp-knife, calling me the Angel of Death, and saying he would kill me, and then I couldn't come for him no more. + I begged, and told him I was only Huck; but he laughed _such_ a screechy laugh, and roared and cussed, and kept on chasing me up. + Once when I turned short and dodged under his arm he made a grab and got me by the jacket between my shoulders, and I thought I was gone; but I slid out of the jacket quick as lightning, and saved myself. + Pretty soon he was all tired out, and dropped down with his back against the door, and said he would rest a minute and then kill me. + He put his knife under him, and said he would sleep and get strong, and then he would see who was who. + So he dozed off pretty soon. + By and by I got the old split-bottom chair and clumb up as easy as I could, not to make any noise, and got down the gun. + I slipped the ramrod down it to make sure it was loaded, then I laid it across the turnip barrel, pointing towards pap, and set down behind it to wait for him to stir. + And how slow and still the time did drag along. + CHAPTER VII. + "GIT up! + What you 'bout?" + I opened my eyes and looked around, trying to make out where I was. + It was after sun-up, and I had been sound asleep. + Pap was standing over me looking sour and sick, too. + He says: "What you doin' with this gun?" + I judged he didn't know nothing about what he had been doing, so I says: "Somebody tried to get in, so I was laying for him." + "Why didn't you roust me out?" + "Well, I tried to, but I couldn't; I couldn't budge you." + "Well, all right. + Don't stand there palavering all day, but out with you and see if there's a fish on the lines for breakfast. + I'll be along in a minute." + He unlocked the door, and I cleared out up the river-bank. + I noticed some pieces of limbs and such things floating down, and a sprinkling of bark; so I knowed the river had begun to rise. + I reckoned I would have great times now if I was over at the town. + The June rise used to be always luck for me; because as soon as that rise begins here comes cordwood floating down, and pieces of log rafts—sometimes a dozen logs together; so all you have to do is to catch them and sell them to the wood-yards and the sawmill. + I went along up the bank with one eye out for pap and t'other one out for what the rise might fetch along. + Well, all at once here comes a canoe; just a beauty, too, about thirteen or fourteen foot long, riding high like a duck. + I shot head-first off of the bank like a frog, clothes and all on, and struck out for the canoe. + I just expected there'd be somebody laying down in it, because people often done that to fool folks, and when a chap had pulled a skiff out most to it they'd raise up and laugh at him. + But it warn't so this time. + It was a drift-canoe sure enough, and I clumb in and paddled her ashore. + Thinks I, the old man will be glad when he sees this—she's worth ten dollars. + But when I got to shore pap wasn't in sight yet, and as I was running her into a little creek like a gully, all hung over with vines and willows, I struck another idea: I judged I'd hide her good, and then, 'stead of taking to the woods when I run off, I'd go down the river about fifty mile and camp in one place for good, and not have such a rough time tramping on foot. + It was pretty close to the shanty, and I thought I heard the old man coming all the time; but I got her hid; and then I out and looked around a bunch of willows, and there was the old man down the path a piece just drawing a bead on a bird with his gun. + So he hadn't seen anything. + When he got along I was hard at it taking up a "trot" line. + He abused me a little for being so slow; but I told him I fell in the river, and that was what made me so long. + I knowed he would see I was wet, and then he would be asking questions. + We got five catfish off the lines and went home. + While we laid off after breakfast to sleep up, both of us being about wore out, I got to thinking that if I could fix up some way to keep pap and the widow from trying to follow me, it would be a certainer thing than trusting to luck to get far enough off before they missed me; you see, all kinds of things might happen. + Well, I didn't see no way for a while, but by and by pap raised up a minute to drink another barrel of water, and he says: "Another time a man comes a-prowling round here you roust me out, you hear? + That man warn't here for no good. + I'd a shot him. + Next time you roust me out, you hear?" + Then he dropped down and went to sleep again; but what he had been saying give me the very idea I wanted. + I says to myself, I can fix it now so nobody won't think of following me. + About twelve o'clock we turned out and went along up the bank. + The river was coming up pretty fast, and lots of driftwood going by on the rise. + By and by along comes part of a log raft—nine logs fast together. + We went out with the skiff and towed it ashore. + Then we had dinner. + Anybody but pap would a waited and seen the day through, so as to catch more stuff; but that warn't pap's style. + Nine logs was enough for one time; he must shove right over to town and sell. + So he locked me in and took the skiff, and started off towing the raft about half-past three. + I judged he wouldn't come back that night. + I waited till I reckoned he had got a good start; then I out with my saw, and went to work on that log again. + Before he was t'other side of the river I was out of the hole; him and his raft was just a speck on the water away off yonder. + I took the sack of corn meal and took it to where the canoe was hid, and shoved the vines and branches apart and put it in; then I done the same with the side of bacon; then the whisky-jug. + I took all the coffee and sugar there was, and all the ammunition; I took the wadding; I took the bucket and gourd; I took a dipper and a tin cup, and my old saw and two blankets, and the skillet and the coffee-pot. + I took fish-lines and matches and other things—everything that was worth a cent. + I cleaned out the place. + I wanted an axe, but there wasn't any, only the one out at the woodpile, and I knowed why I was going to leave that. + I fetched out the gun, and now I was done. + I had wore the ground a good deal crawling out of the hole and dragging out so many things. + So I fixed that as good as I could from the outside by scattering dust on the place, which covered up the smoothness and the sawdust. + Then I fixed the piece of log back into its place, and put two rocks under it and one against it to hold it there, for it was bent up at that place and didn't quite touch ground. + If you stood four or five foot away and didn't know it was sawed, you wouldn't never notice it; and besides, this was the back of the cabin, and it warn't likely anybody would go fooling around there. + It was all grass clear to the canoe, so I hadn't left a track. + I followed around to see. + I stood on the bank and looked out over the river. + All safe. + So I took the gun and went up a piece into the woods, and was hunting around for some birds when I see a wild pig; hogs soon went wild in them bottoms after they had got away from the prairie farms. + I shot this fellow and took him into camp. + I took the axe and smashed in the door. + I beat it and hacked it considerable a-doing it. + I fetched the pig in, and took him back nearly to the table and hacked into his throat with the axe, and laid him down on the ground to bleed; I say ground because it was ground—hard packed, and no boards. + Well, next I took an old sack and put a lot of big rocks in it—all I could drag—and I started it from the pig, and dragged it to the door and through the woods down to the river and dumped it in, and down it sunk, out of sight. + You could easy see that something had been dragged over the ground. + I did wish Tom Sawyer was there; I knowed he would take an interest in this kind of business, and throw in the fancy touches. + Nobody could spread himself like Tom Sawyer in such a thing as that. + Well, last I pulled out some of my hair, and blooded the axe good, and stuck it on the back side, and slung the axe in the corner. + Then I took up the pig and held him to my breast with my jacket (so he couldn't drip) till I got a good piece below the house and then dumped him into the river. + Now I thought of something else. + So I went and got the bag of meal and my old saw out of the canoe, and fetched them to the house. + I took the bag to where it used to stand, and ripped a hole in the bottom of it with the saw, for there warn't no knives and forks on the place—pap done everything with his clasp-knife about the cooking. + Then I carried the sack about a hundred yards across the grass and through the willows east of the house, to a shallow lake that was five mile wide and full of rushes—and ducks too, you might say, in the season. + There was a slough or a creek leading out of it on the other side that went miles away, I don't know where, but it didn't go to the river. + The meal sifted out and made a little track all the way to the lake. + I dropped pap's whetstone there too, so as to look like it had been done by accident. + Then I tied up the rip in the meal sack with a string, so it wouldn't leak no more, and took it and my saw to the canoe again. + It was about dark now; so I dropped the canoe down the river under some willows that hung over the bank, and waited for the moon to rise. + I made fast to a willow; then I took a bite to eat, and by and by laid down in the canoe to smoke a pipe and lay out a plan. + I says to myself, they'll follow the track of that sackful of rocks to the shore and then drag the river for me. + And they'll follow that meal track to the lake and go browsing down the creek that leads out of it to find the robbers that killed me and took the things. + They won't ever hunt the river for anything but my dead carcass. + They'll soon get tired of that, and won't bother no more about me. + All right; I can stop anywhere I want to. + Jackson's Island is good enough for me; I know that island pretty well, and nobody ever comes there. + And then I can paddle over to town nights, and slink around and pick up things I want. + Jackson's Island's the place. + I was pretty tired, and the first thing I knowed I was asleep. + When I woke up I didn't know where I was for a minute. + I set up and looked around, a little scared. + Then I remembered. + The river looked miles and miles across. + The moon was so bright I could a counted the drift logs that went a-slipping along, black and still, hundreds of yards out from shore. + Everything was dead quiet, and it looked late, and _smelt_ late. + You know what I mean—I don't know the words to put it in. + I took a good gap and a stretch, and was just going to unhitch and start when I heard a sound away over the water. + I listened. + Pretty soon I made it out. + It was that dull kind of a regular sound that comes from oars working in rowlocks when it's a still night. + I peeped out through the willow branches, and there it was—a skiff, away across the water. + I couldn't tell how many was in it. + It kept a-coming, and when it was abreast of me I see there warn't but one man in it. + Think's I, maybe it's pap, though I warn't expecting him. + He dropped below me with the current, and by and by he came a-swinging up shore in the easy water, and he went by so close I could a reached out the gun and touched him. + Well, it _was_ pap, sure enough—and sober, too, by the way he laid his oars. + I didn't lose no time. + The next minute I was a-spinning down stream soft but quick in the shade of the bank. + I made two mile and a half, and then struck out a quarter of a mile or more towards the middle of the river, because pretty soon I would be passing the ferry landing, and people might see me and hail me. + I got out amongst the driftwood, and then laid down in the bottom of the canoe and let her float. + I laid there, and had a good rest and a smoke out of my pipe, looking away into the sky; not a cloud in it. + The sky looks ever so deep when you lay down on your back in the moonshine; I never knowed it before. + And how far a body can hear on the water such nights! + I heard people talking at the ferry landing. + I heard what they said, too—every word of it. + One man said it was getting towards the long days and the short nights now. + T'other one said _this_ warn't one of the short ones, he reckoned—and then they laughed, and he said it over again, and they laughed again; then they waked up another fellow and told him, and laughed, but he didn't laugh; he ripped out something brisk, and said let him alone. + The first fellow said he 'lowed to tell it to his old woman—she would think it was pretty good; but he said that warn't nothing to some things he had said in his time. + I heard one man say it was nearly three o'clock, and he hoped daylight wouldn't wait more than about a week longer. + After that the talk got further and further away, and I couldn't make out the words any more; but I could hear the mumble, and now and then a laugh, too, but it seemed a long ways off. + I was away below the ferry now. + I rose up, and there was Jackson's Island, about two mile and a half down stream, heavy timbered and standing up out of the middle of the river, big and dark and solid, like a steamboat without any lights. + There warn't any signs of the bar at the head—it was all under water now. + It didn't take me long to get there. + I shot past the head at a ripping rate, the current was so swift, and then I got into the dead water and landed on the side towards the Illinois shore. + I run the canoe into a deep dent in the bank that I knowed about; I had to part the willow branches to get in; and when I made fast nobody could a seen the canoe from the outside. + I went up and set down on a log at the head of the island, and looked out on the big river and the black driftwood and away over to the town, three mile away, where there was three or four lights twinkling. + A monstrous big lumber-raft was about a mile up stream, coming along down, with a lantern in the middle of it. + I watched it come creeping down, and when it was most abreast of where I stood I heard a man say, "Stern oars, there! + heave her head to stabboard!" + I heard that just as plain as if the man was by my side. + There was a little gray in the sky now; so I stepped into the woods, and laid down for a nap before breakfast. + CHAPTER VIII. + THE sun was up so high when I waked that I judged it was after eight o'clock. + I laid there in the grass and the cool shade thinking about things, and feeling rested and ruther comfortable and satisfied. + I could see the sun out at one or two holes, but mostly it was big trees all about, and gloomy in there amongst them. + There was freckled places on the ground where the light sifted down through the leaves, and the freckled places swapped about a little, showing there was a little breeze up there. + A couple of squirrels set on a limb and jabbered at me very friendly. + I was powerful lazy and comfortable—didn't want to get up and cook breakfast. + Well, I was dozing off again when I thinks I hears a deep sound of "boom!" + away up the river. + I rouses up, and rests on my elbow and listens; pretty soon I hears it again. + I hopped up, and went and looked out at a hole in the leaves, and I see a bunch of smoke laying on the water a long ways up—about abreast the ferry. + And there was the ferryboat full of people floating along down. + I knowed what was the matter now. + "Boom!" + I see the white smoke squirt out of the ferryboat's side. + You see, they was firing cannon over the water, trying to make my carcass come to the top. + I was pretty hungry, but it warn't going to do for me to start a fire, because they might see the smoke. + So I set there and watched the cannon-smoke and listened to the boom. + The river was a mile wide there, and it always looks pretty on a summer morning—so I was having a good enough time seeing them hunt for my remainders if I only had a bite to eat. + Well, then I happened to think how they always put quicksilver in loaves of bread and float them off, because they always go right to the drownded carcass and stop there. + So, says I, I'll keep a lookout, and if any of them's floating around after me I'll give them a show. + I changed to the Illinois edge of the island to see what luck I could have, and I warn't disappointed. + A big double loaf come along, and I most got it with a long stick, but my foot slipped and she floated out further. + Of course I was where the current set in the closest to the shore—I knowed enough for that. + But by and by along comes another one, and this time I won. + I took out the plug and shook out the little dab of quicksilver, and set my teeth in. + It was "baker's bread"—what the quality eat; none of your low-down corn-pone. + I got a good place amongst the leaves, and set there on a log, munching the bread and watching the ferry-boat, and very well satisfied. + And then something struck me. + I says, now I reckon the widow or the parson or somebody prayed that this bread would find me, and here it has gone and done it. + So there ain't no doubt but there is something in that thing—that is, there's something in it when a body like the widow or the parson prays, but it don't work for me, and I reckon it don't work for only just the right kind. + I lit a pipe and had a good long smoke, and went on watching. + The ferryboat was floating with the current, and I allowed I'd have a chance to see who was aboard when she come along, because she would come in close, where the bread did. + When she'd got pretty well along down towards me, I put out my pipe and went to where I fished out the bread, and laid down behind a log on the bank in a little open place. + Where the log forked I could peep through. + By and by she come along, and she drifted in so close that they could a run out a plank and walked ashore. + Most everybody was on the boat. + Pap, and Judge Thatcher, and Bessie Thatcher, and Jo Harper, and Tom Sawyer, and his old Aunt Polly, and Sid and Mary, and plenty more. + Everybody was talking about the murder, but the captain broke in and says: "Look sharp, now; the current sets in the closest here, and maybe he's washed ashore and got tangled amongst the brush at the water's edge. + I hope so, anyway." + I didn't hope so. + They all crowded up and leaned over the rails, nearly in my face, and kept still, watching with all their might. + I could see them first-rate, but they couldn't see me. + Then the captain sung out: "Stand away!" + and the cannon let off such a blast right before me that it made me deef with the noise and pretty near blind with the smoke, and I judged I was gone. + If they'd a had some bullets in, I reckon they'd a got the corpse they was after. + Well, I see I warn't hurt, thanks to goodness. + The boat floated on and went out of sight around the shoulder of the island. + I could hear the booming now and then, further and further off, and by and by, after an hour, I didn't hear it no more. + The island was three mile long. + I judged they had got to the foot, and was giving it up. + But they didn't yet a while. + They turned around the foot of the island and started up the channel on the Missouri side, under steam, and booming once in a while as they went. + I crossed over to that side and watched them. + When they got abreast the head of the island they quit shooting and dropped over to the Missouri shore and went home to the town. + I knowed I was all right now. + Nobody else would come a-hunting after me. + I got my traps out of the canoe and made me a nice camp in the thick woods. + I made a kind of a tent out of my blankets to put my things under so the rain couldn't get at them. + I catched a catfish and haggled him open with my saw, and towards sundown I started my camp fire and had supper. + Then I set out a line to catch some fish for breakfast. + When it was dark I set by my camp fire smoking, and feeling pretty well satisfied; but by and by it got sort of lonesome, and so I went and set on the bank and listened to the current swashing along, and counted the stars and drift logs and rafts that come down, and then went to bed; there ain't no better way to put in time when you are lonesome; you can't stay so, you soon get over it. + And so for three days and nights. + No difference—just the same thing. + But the next day I went exploring around down through the island. + I was boss of it; it all belonged to me, so to say, and I wanted to know all about it; but mainly I wanted to put in the time. + I found plenty strawberries, ripe and prime; and green summer grapes, and green razberries; and the green blackberries was just beginning to show. + They would all come handy by and by, I judged. + Well, I went fooling along in the deep woods till I judged I warn't far from the foot of the island. + I had my gun along, but I hadn't shot nothing; it was for protection; thought I would kill some game nigh home. + About this time I mighty near stepped on a good-sized snake, and it went sliding off through the grass and flowers, and I after it, trying to get a shot at it. + I clipped along, and all of a sudden I bounded right on to the ashes of a camp fire that was still smoking. + My heart jumped up amongst my lungs. + I never waited for to look further, but uncocked my gun and went sneaking back on my tiptoes as fast as ever I could. + Every now and then I stopped a second amongst the thick leaves and listened, but my breath come so hard I couldn't hear nothing else. + I slunk along another piece further, then listened again; and so on, and so on. + If I see a stump, I took it for a man; if I trod on a stick and broke it, it made me feel like a person had cut one of my breaths in two and I only got half, and the short half, too. + When I got to camp I warn't feeling very brash, there warn't much sand in my craw; but I says, this ain't no time to be fooling around. + So I got all my traps into my canoe again so as to have them out of sight, and I put out the fire and scattered the ashes around to look like an old last year's camp, and then clumb a tree. + I reckon I was up in the tree two hours; but I didn't see nothing, I didn't hear nothing—I only _thought_ I heard and seen as much as a thousand things. + Well, I couldn't stay up there forever; so at last I got down, but I kept in the thick woods and on the lookout all the time. + All I could get to eat was berries and what was left over from breakfast. + By the time it was night I was pretty hungry. + So when it was good and dark I slid out from shore before moonrise and paddled over to the Illinois bank—about a quarter of a mile. + I went out in the woods and cooked a supper, and I had about made up my mind I would stay there all night when I hear a _plunkety-plunk, plunkety-plunk_, and says to myself, horses coming; and next I hear people's voices. + I got everything into the canoe as quick as I could, and then went creeping through the woods to see what I could find out. + I hadn't got far when I hear a man say: "We better camp here if we can find a good place; the horses is about beat out. + Let's look around." + I didn't wait, but shoved out and paddled away easy. + I tied up in the old place, and reckoned I would sleep in the canoe. + I didn't sleep much. + I couldn't, somehow, for thinking. + And every time I waked up I thought somebody had me by the neck. + So the sleep didn't do me no good. + By and by I says to myself, I can't live this way; I'm a-going to find out who it is that's here on the island with me; I'll find it out or bust. + Well, I felt better right off. + So I took my paddle and slid out from shore just a step or two, and then let the canoe drop along down amongst the shadows. + The moon was shining, and outside of the shadows it made it most as light as day. + I poked along well on to an hour, everything still as rocks and sound asleep. + Well, by this time I was most down to the foot of the island. + A little ripply, cool breeze begun to blow, and that was as good as saying the night was about done. + I give her a turn with the paddle and brung her nose to shore; then I got my gun and slipped out and into the edge of the woods. + I sat down there on a log, and looked out through the leaves. + I see the moon go off watch, and the darkness begin to blanket the river. + But in a little while I see a pale streak over the treetops, and knowed the day was coming. + So I took my gun and slipped off towards where I had run across that camp fire, stopping every minute or two to listen. + But I hadn't no luck somehow; I couldn't seem to find the place. + But by and by, sure enough, I catched a glimpse of fire away through the trees. + I went for it, cautious and slow. + By and by I was close enough to have a look, and there laid a man on the ground. + It most give me the fan-tods. + He had a blanket around his head, and his head was nearly in the fire. + I set there behind a clump of bushes, in about six foot of him, and kept my eyes on him steady. + It was getting gray daylight now. + Pretty soon he gapped and stretched himself and hove off the blanket, and it was Miss Watson's Jim! + I bet I was glad to see him. + I says: "Hello, Jim!" + and skipped out. + He bounced up and stared at me wild. + Then he drops down on his knees, and puts his hands together and says: "Doan' hurt me—don't! + I hain't ever done no harm to a ghos'. + I alwuz liked dead people, en done all I could for 'em. + You go en git in de river agin, whah you b'longs, en doan' do nuffn to Ole Jim, 'at 'uz awluz yo' fren'." + Well, I warn't long making him understand I warn't dead. + I was ever so glad to see Jim. + I warn't lonesome now. + I told him I warn't afraid of _him_ telling the people where I was. + I talked along, but he only set there and looked at me; never said nothing. + Then I says: "It's good daylight. + Le's get breakfast. + Make up your camp fire good." + "What's de use er makin' up de camp fire to cook strawbries en sich truck? + But you got a gun, hain't you? + Den we kin git sumfn better den strawbries." + "Strawberries and such truck," I says. + "Is that what you live on?" + "I couldn' git nuffn else," he says. + "Why, how long you been on the island, Jim?" + "I come heah de night arter you's killed." + "What, all that time?" + "Yes—indeedy." + "And ain't you had nothing but that kind of rubbage to eat?" + "No, sah—nuffn else." + "Well, you must be most starved, ain't you?" + "I reck'n I could eat a hoss. + I think I could. + How long you ben on de islan'?" + "Since the night I got killed." + "No! + W'y, what has you lived on? + But you got a gun. + Oh, yes, you got a gun. + Dat's good. + Now you kill sumfn en I'll make up de fire." + So we went over to where the canoe was, and while he built a fire in a grassy open place amongst the trees, I fetched meal and bacon and coffee, and coffee-pot and frying-pan, and sugar and tin cups, and the nigger was set back considerable, because he reckoned it was all done with witchcraft. + I catched a good big catfish, too, and Jim cleaned him with his knife, and fried him. + When breakfast was ready we lolled on the grass and eat it smoking hot. + Jim laid it in with all his might, for he was most about starved. + Then when we had got pretty well stuffed, we laid off and lazied. + By and by Jim says: "But looky here, Huck, who wuz it dat 'uz killed in dat shanty ef it warn't you?" + Then I told him the whole thing, and he said it was smart. + He said Tom Sawyer couldn't get up no better plan than what I had. + Then I says: "How do you come to be here, Jim, and how'd you get here?" + He looked pretty uneasy, and didn't say nothing for a minute. + Then he says: "Maybe I better not tell." + "Why, Jim?" + "Well, dey's reasons. + But you wouldn' tell on me ef I uz to tell you, would you, Huck?" + "Blamed if I would, Jim." + "Well, I b'lieve you, Huck. + I—_I run off_." + "Jim!" + "But mind, you said you wouldn' tell—you know you said you wouldn' tell, Huck." + "Well, I did. + I said I wouldn't, and I'll stick to it. + Honest _injun_, I will. + People would call me a low-down Abolitionist and despise me for keeping mum—but that don't make no difference. + I ain't a-going to tell, and I ain't a-going back there, anyways. + So, now, le's know all about it." + "Well, you see, it 'uz dis way. + Ole missus—dat's Miss Watson—she pecks on me all de time, en treats me pooty rough, but she awluz said she wouldn' sell me down to Orleans. + But I noticed dey wuz a nigger trader roun' de place considable lately, en I begin to git oneasy. + Well, one night I creeps to de do' pooty late, en de do' warn't quite shet, en I hear old missus tell de widder she gwyne to sell me down to Orleans, but she didn' want to, but she could git eight hund'd dollars for me, en it 'uz sich a big stack o' money she couldn' resis'. + De widder she try to git her to say she wouldn' do it, but I never waited to hear de res'. + I lit out mighty quick, I tell you. + "I tuck out en shin down de hill, en 'spec to steal a skift 'long de sho' som'ers 'bove de town, but dey wuz people a-stirring yit, so I hid in de ole tumble-down cooper-shop on de bank to wait for everybody to go 'way. + Well, I wuz dah all night. + Dey wuz somebody roun' all de time. + 'Long 'bout six in de mawnin' skifts begin to go by, en 'bout eight er nine every skift dat went 'long wuz talkin' 'bout how yo' pap come over to de town en say you's killed. + Dese las' skifts wuz full o' ladies en genlmen a-goin' over for to see de place. + Sometimes dey'd pull up at de sho' en take a res' b'fo' dey started acrost, so by de talk I got to know all 'bout de killin'. + I 'uz powerful sorry you's killed, Huck, but I ain't no mo' now. + "I laid dah under de shavin's all day. + I 'uz hungry, but I warn't afeard; bekase I knowed ole missus en de widder wuz goin' to start to de camp-meet'n' right arter breakfas' en be gone all day, en dey knows I goes off wid de cattle 'bout daylight, so dey wouldn' 'spec to see me roun' de place, en so dey wouldn' miss me tell arter dark in de evenin'. + De yuther servants wouldn' miss me, kase dey'd shin out en take holiday soon as de ole folks 'uz out'n de way. + "Well, when it come dark I tuck out up de river road, en went 'bout two mile er more to whah dey warn't no houses. + I'd made up my mine 'bout what I's agwyne to do. + You see, ef I kep' on tryin' to git away afoot, de dogs 'ud track me; ef I stole a skift to cross over, dey'd miss dat skift, you see, en dey'd know 'bout whah I'd lan' on de yuther side, en whah to pick up my track. + So I says, a raff is what I's arter; it doan' _make_ no track. + "I see a light a-comin' roun' de p'int bymeby, so I wade' in en shove' a log ahead o' me en swum more'n half way acrost de river, en got in 'mongst de drift-wood, en kep' my head down low, en kinder swum agin de current tell de raff come along. + Den I swum to de stern uv it en tuck a-holt. + It clouded up en 'uz pooty dark for a little while. + So I clumb up en laid down on de planks. + De men 'uz all 'way yonder in de middle, whah de lantern wuz. + De river wuz a-risin', en dey wuz a good current; so I reck'n'd 'at by fo' in de mawnin' I'd be twenty-five mile down de river, en den I'd slip in jis b'fo' daylight en swim asho', en take to de woods on de Illinois side. + "But I didn' have no luck. + When we 'uz mos' down to de head er de islan' a man begin to come aft wid de lantern, I see it warn't no use fer to wait, so I slid overboard en struck out fer de islan'. + Well, I had a notion I could lan' mos' anywhers, but I couldn't—bank too bluff. + I 'uz mos' to de foot er de islan' b'fo' I found' a good place. + I went into de woods en jedged I wouldn' fool wid raffs no mo', long as dey move de lantern roun' so. + I had my pipe en a plug er dog-leg, en some matches in my cap, en dey warn't wet, so I 'uz all right." + "And so you ain't had no meat nor bread to eat all this time? + Why didn't you get mud-turkles?" + "How you gwyne to git 'm? + You can't slip up on um en grab um; en how's a body gwyne to hit um wid a rock? + How could a body do it in de night? + En I warn't gwyne to show mysef on de bank in de daytime." + "Well, that's so. + You've had to keep in the woods all the time, of course. + Did you hear 'em shooting the cannon?" + "Oh, yes. + I knowed dey was arter you. + I see um go by heah—watched um thoo de bushes." + Some young birds come along, flying a yard or two at a time and lighting. + Jim said it was a sign it was going to rain. + He said it was a sign when young chickens flew that way, and so he reckoned it was the same way when young birds done it. + I was going to catch some of them, but Jim wouldn't let me. + He said it was death. + He said his father laid mighty sick once, and some of them catched a bird, and his old granny said his father would die, and he did. + And Jim said you mustn't count the things you are going to cook for dinner, because that would bring bad luck. + The same if you shook the table-cloth after sundown. + And he said if a man owned a beehive and that man died, the bees must be told about it before sun-up next morning, or else the bees would all weaken down and quit work and die. + Jim said bees wouldn't sting idiots; but I didn't believe that, because I had tried them lots of times myself, and they wouldn't sting me. + I had heard about some of these things before, but not all of them. + Jim knowed all kinds of signs. + He said he knowed most everything. + I said it looked to me like all the signs was about bad luck, and so I asked him if there warn't any good-luck signs. + He says: "Mighty few—an' _dey_ ain't no use to a body. + What you want to know when good luck's a-comin' for? + Want to keep it off?" + And he said: "Ef you's got hairy arms en a hairy breas', it's a sign dat you's agwyne to be rich. + Well, dey's some use in a sign like dat, 'kase it's so fur ahead. + You see, maybe you's got to be po' a long time fust, en so you might git discourage' en kill yo'sef 'f you didn' know by de sign dat you gwyne to be rich bymeby." + "Have you got hairy arms and a hairy breast, Jim?" + "What's de use to ax dat question? + Don't you see I has?" + "Well, are you rich?" + "No, but I ben rich wunst, and gwyne to be rich agin. + Wunst I had foteen dollars, but I tuck to specalat'n', en got busted out." + "What did you speculate in, Jim?" + "Well, fust I tackled stock." + "What kind of stock?" + "Why, live stock—cattle, you know. + I put ten dollars in a cow. + But I ain' gwyne to resk no mo' money in stock. + De cow up 'n' died on my han's." + "So you lost the ten dollars." + "No, I didn't lose it all. + I on'y los' 'bout nine of it. + I sole de hide en taller for a dollar en ten cents." + "You had five dollars and ten cents left. + Did you speculate any more?" + "Yes. + You know that one-laigged nigger dat b'longs to old Misto Bradish? + Well, he sot up a bank, en say anybody dat put in a dollar would git fo' dollars mo' at de en' er de year. + Well, all de niggers went in, but dey didn't have much. + I wuz de on'y one dat had much. + So I stuck out for mo' dan fo' dollars, en I said 'f I didn' git it I'd start a bank mysef. + Well, o' course dat nigger want' to keep me out er de business, bekase he says dey warn't business 'nough for two banks, so he say I could put in my five dollars en he pay me thirty-five at de en' er de year. + "So I done it. + Den I reck'n'd I'd inves' de thirty-five dollars right off en keep things a-movin'. + Dey wuz a nigger name' Bob, dat had ketched a wood-flat, en his marster didn' know it; en I bought it off'n him en told him to take de thirty-five dollars when de en' er de year come; but somebody stole de wood-flat dat night, en nex day de one-laigged nigger say de bank's busted. + So dey didn' none uv us git no money." + "What did you do with the ten cents, Jim?" + "Well, I 'uz gwyne to spen' it, but I had a dream, en de dream tole me to give it to a nigger name' Balum—Balum's Ass dey call him for short; he's one er dem chuckleheads, you know. + But he's lucky, dey say, en I see I warn't lucky. + De dream say let Balum inves' de ten cents en he'd make a raise for me. + Well, Balum he tuck de money, en when he wuz in church he hear de preacher say dat whoever give to de po' len' to de Lord, en boun' to git his money back a hund'd times. + So Balum he tuck en give de ten cents to de po', en laid low to see what wuz gwyne to come of it." + "Well, what did come of it, Jim?" + "Nuffn never come of it. + I couldn' manage to k'leck dat money no way; en Balum he couldn'. + I ain' gwyne to len' no mo' money 'dout I see de security. + Boun' to git yo' money back a hund'd times, de preacher says! + Ef I could git de ten _cents_ back, I'd call it squah, en be glad er de chanst." + "Well, it's all right anyway, Jim, long as you're going to be rich again some time or other." + "Yes; en I's rich now, come to look at it. + I owns mysef, en I's wuth eight hund'd dollars. + I wisht I had de money, I wouldn' want no mo'." + CHAPTER IX. + I wanted to go and look at a place right about the middle of the island that I'd found when I was exploring; so we started and soon got to it, because the island was only three miles long and a quarter of a mile wide. + This place was a tolerable long, steep hill or ridge about forty foot high. + We had a rough time getting to the top, the sides was so steep and the bushes so thick. + We tramped and clumb around all over it, and by and by found a good big cavern in the rock, most up to the top on the side towards Illinois. + The cavern was as big as two or three rooms bunched together, and Jim could stand up straight in it. + It was cool in there. + Jim was for putting our traps in there right away, but I said we didn't want to be climbing up and down there all the time. + Jim said if we had the canoe hid in a good place, and had all the traps in the cavern, we could rush there if anybody was to come to the island, and they would never find us without dogs. + And, besides, he said them little birds had said it was going to rain, and did I want the things to get wet? + So we went back and got the canoe, and paddled up abreast the cavern, and lugged all the traps up there. + Then we hunted up a place close by to hide the canoe in, amongst the thick willows. + We took some fish off of the lines and set them again, and begun to get ready for dinner. + The door of the cavern was big enough to roll a hogshead in, and on one side of the door the floor stuck out a little bit, and was flat and a good place to build a fire on. + So we built it there and cooked dinner. + We spread the blankets inside for a carpet, and eat our dinner in there. + We put all the other things handy at the back of the cavern. + Pretty soon it darkened up, and begun to thunder and lighten; so the birds was right about it. + Directly it begun to rain, and it rained like all fury, too, and I never see the wind blow so. + It was one of these regular summer storms. + It would get so dark that it looked all blue-black outside, and lovely; and the rain would thrash along by so thick that the trees off a little ways looked dim and spider-webby; and here would come a blast of wind that would bend the trees down and turn up the pale underside of the leaves; and then a perfect ripper of a gust would follow along and set the branches to tossing their arms as if they was just wild; and next, when it was just about the bluest and blackest—_FST_! + it was as bright as glory, and you'd have a little glimpse of tree-tops a-plunging about away off yonder in the storm, hundreds of yards further than you could see before; dark as sin again in a second, and now you'd hear the thunder let go with an awful crash, and then go rumbling, grumbling, tumbling, down the sky towards the under side of the world, like rolling empty barrels down stairs—where it's long stairs and they bounce a good deal, you know. + "Jim, this is nice," I says. + "I wouldn't want to be nowhere else but here. + Pass me along another hunk of fish and some hot corn-bread." + "Well, you wouldn't a ben here 'f it hadn't a ben for Jim. + You'd a ben down dah in de woods widout any dinner, en gittn' mos' drownded, too; dat you would, honey. + Chickens knows when it's gwyne to rain, en so do de birds, chile." + The river went on raising and raising for ten or twelve days, till at last it was over the banks. + The water was three or four foot deep on the island in the low places and on the Illinois bottom. + On that side it was a good many miles wide, but on the Missouri side it was the same old distance across—a half a mile—because the Missouri shore was just a wall of high bluffs. + Daytimes we paddled all over the island in the canoe, It was mighty cool and shady in the deep woods, even if the sun was blazing outside. + We went winding in and out amongst the trees, and sometimes the vines hung so thick we had to back away and go some other way. + Well, on every old broken-down tree you could see rabbits and snakes and such things; and when the island had been overflowed a day or two they got so tame, on account of being hungry, that you could paddle right up and put your hand on them if you wanted to; but not the snakes and turtles—they would slide off in the water. + The ridge our cavern was in was full of them. + We could a had pets enough if we'd wanted them. + One night we catched a little section of a lumber raft—nice pine planks. + It was twelve foot wide and about fifteen or sixteen foot long, and the top stood above water six or seven inches—a solid, level floor. + We could see saw-logs go by in the daylight sometimes, but we let them go; we didn't show ourselves in daylight. + Another night when we was up at the head of the island, just before daylight, here comes a frame-house down, on the west side. + She was a two-story, and tilted over considerable. + We paddled out and got aboard—clumb in at an upstairs window. + But it was too dark to see yet, so we made the canoe fast and set in her to wait for daylight. + The light begun to come before we got to the foot of the island. + Then we looked in at the window. + We could make out a bed, and a table, and two old chairs, and lots of things around about on the floor, and there was clothes hanging against the wall. + There was something laying on the floor in the far corner that looked like a man. + So Jim says: + "Hello, you!" + But it didn't budge. + So I hollered again, and then Jim says: + "De man ain't asleep—he's dead. + You hold still—I'll go en see." + He went, and bent down and looked, and says: + "It's a dead man. + Yes, indeedy; naked, too. + He's ben shot in de back. + I reck'n he's ben dead two er three days. + Come in, Huck, but doan' look at his face—it's too gashly." + I didn't look at him at all. + Jim throwed some old rags over him, but he needn't done it; I didn't want to see him. + There was heaps of old greasy cards scattered around over the floor, and old whisky bottles, and a couple of masks made out of black cloth; and all over the walls was the ignorantest kind of words and pictures made with charcoal. + There was two old dirty calico dresses, and a sun-bonnet, and some women's underclothes hanging against the wall, and some men's clothing, too. + We put the lot into the canoe—it might come good. + There was a boy's old speckled straw hat on the floor; I took that, too. + And there was a bottle that had had milk in it, and it had a rag stopper for a baby to suck. + We would a took the bottle, but it was broke. + There was a seedy old chest, and an old hair trunk with the hinges broke. + They stood open, but there warn't nothing left in them that was any account. + The way things was scattered about we reckoned the people left in a hurry, and warn't fixed so as to carry off most of their stuff. + We got an old tin lantern, and a butcher-knife without any handle, and a bran-new Barlow knife worth two bits in any store, and a lot of tallow candles, and a tin candlestick, and a gourd, and a tin cup, and a ratty old bedquilt off the bed, and a reticule with needles and pins and beeswax and buttons and thread and all such truck in it, and a hatchet and some nails, and a fishline as thick as my little finger with some monstrous hooks on it, and a roll of buckskin, and a leather dog-collar, and a horseshoe, and some vials of medicine that didn't have no label on them; and just as we was leaving I found a tolerable good curry-comb, and Jim he found a ratty old fiddle-bow, and a wooden leg. + The straps was broke off of it, but, barring that, it was a good enough leg, though it was too long for me and not long enough for Jim, and we couldn't find the other one, though we hunted all around. + And so, take it all around, we made a good haul. + When we was ready to shove off we was a quarter of a mile below the island, and it was pretty broad day; so I made Jim lay down in the canoe and cover up with the quilt, because if he set up people could tell he was a nigger a good ways off. + I paddled over to the Illinois shore, and drifted down most a half a mile doing it. + I crept up the dead water under the bank, and hadn't no accidents and didn't see nobody. + We got home all safe. + CHAPTER X. + AFTER breakfast I wanted to talk about the dead man and guess out how he come to be killed, but Jim didn't want to. + He said it would fetch bad luck; and besides, he said, he might come and ha'nt us; he said a man that warn't buried was more likely to go a-ha'nting around than one that was planted and comfortable. + That sounded pretty reasonable, so I didn't say no more; but I couldn't keep from studying over it and wishing I knowed who shot the man, and what they done it for. + We rummaged the clothes we'd got, and found eight dollars in silver sewed up in the lining of an old blanket overcoat. + Jim said he reckoned the people in that house stole the coat, because if they'd a knowed the money was there they wouldn't a left it. + I said I reckoned they killed him, too; but Jim didn't want to talk about that. + I says: + "Now you think it's bad luck; but what did you say when I fetched in the snake-skin that I found on the top of the ridge day before yesterday? + You said it was the worst bad luck in the world to touch a snake-skin with my hands. + Well, here's your bad luck! + We've raked in all this truck and eight dollars besides. + I wish we could have some bad luck like this every day, Jim." + "Never you mind, honey, never you mind. + Don't you git too peart. + It's a-comin'. + Mind I tell you, it's a-comin'." + It did come, too. + It was a Tuesday that we had that talk. + Well, after dinner Friday we was laying around in the grass at the upper end of the ridge, and got out of tobacco. + I went to the cavern to get some, and found a rattlesnake in there. + I killed him, and curled him up on the foot of Jim's blanket, ever so natural, thinking there'd be some fun when Jim found him there. + Well, by night I forgot all about the snake, and when Jim flung himself down on the blanket while I struck a light the snake's mate was there, and bit him. + He jumped up yelling, and the first thing the light showed was the varmint curled up and ready for another spring. + I laid him out in a second with a stick, and Jim grabbed pap's whisky-jug and begun to pour it down. + He was barefooted, and the snake bit him right on the heel. + That all comes of my being such a fool as to not remember that wherever you leave a dead snake its mate always comes there and curls around it. + Jim told me to chop off the snake's head and throw it away, and then skin the body and roast a piece of it. + I done it, and he eat it and said it would help cure him. + He made me take off the rattles and tie them around his wrist, too. + He said that that would help. + Then I slid out quiet and throwed the snakes clear away amongst the bushes; for I warn't going to let Jim find out it was all my fault, not if I could help it. + Jim sucked and sucked at the jug, and now and then he got out of his head and pitched around and yelled; but every time he come to himself he went to sucking at the jug again. + His foot swelled up pretty big, and so did his leg; but by and by the drunk begun to come, and so I judged he was all right; but I'd druther been bit with a snake than pap's whisky. + Jim was laid up for four days and nights. + Then the swelling was all gone and he was around again. + I made up my mind I wouldn't ever take a-holt of a snake-skin again with my hands, now that I see what had come of it. + Jim said he reckoned I would believe him next time. + And he said that handling a snake-skin was such awful bad luck that maybe we hadn't got to the end of it yet. + He said he druther see the new moon over his left shoulder as much as a thousand times than take up a snake-skin in his hand. + Well, I was getting to feel that way myself, though I've always reckoned that looking at the new moon over your left shoulder is one of the carelessest and foolishest things a body can do. + Old Hank Bunker done it once, and bragged about it; and in less than two years he got drunk and fell off of the shot-tower, and spread himself out so that he was just a kind of a layer, as you may say; and they slid him edgeways between two barn doors for a coffin, and buried him so, so they say, but I didn't see it. + Pap told me. + But anyway it all come of looking at the moon that way, like a fool. + Well, the days went along, and the river went down between its banks again; and about the first thing we done was to bait one of the big hooks with a skinned rabbit and set it and catch a catfish that was as big as a man, being six foot two inches long, and weighed over two hundred pounds. + We couldn't handle him, of course; he would a flung us into Illinois. + We just set there and watched him rip and tear around till he drownded. + We found a brass button in his stomach and a round ball, and lots of rubbage. + We split the ball open with the hatchet, and there was a spool in it. + Jim said he'd had it there a long time, to coat it over so and make a ball of it. + It was as big a fish as was ever catched in the Mississippi, I reckon. + Jim said he hadn't ever seen a bigger one. + He would a been worth a good deal over at the village. + They peddle out such a fish as that by the pound in the market-house there; everybody buys some of him; his meat's as white as snow and makes a good fry. + Next morning I said it was getting slow and dull, and I wanted to get a stirring up some way. + I said I reckoned I would slip over the river and find out what was going on. + Jim liked that notion; but he said I must go in the dark and look sharp. + Then he studied it over and said, couldn't I put on some of them old things and dress up like a girl? + That was a good notion, too. + So we shortened up one of the calico gowns, and I turned up my trouser-legs to my knees and got into it. + Jim hitched it behind with the hooks, and it was a fair fit. + I put on the sun-bonnet and tied it under my chin, and then for a body to look in and see my face was like looking down a joint of stove-pipe. + Jim said nobody would know me, even in the daytime, hardly. + I practiced around all day to get the hang of the things, and by and by I could do pretty well in them, only Jim said I didn't walk like a girl; and he said I must quit pulling up my gown to get at my britches-pocket. + I took notice, and done better. + I started up the Illinois shore in the canoe just after dark. + I started across to the town from a little below the ferry-landing, and the drift of the current fetched me in at the bottom of the town. + I tied up and started along the bank. + There was a light burning in a little shanty that hadn't been lived in for a long time, and I wondered who had took up quarters there. + I slipped up and peeped in at the window. + There was a woman about forty year old in there knitting by a candle that was on a pine table. + I didn't know her face; she was a stranger, for you couldn't start a face in that town that I didn't know. + Now this was lucky, because I was weakening; I was getting afraid I had come; people might know my voice and find me out. + But if this woman had been in such a little town two days she could tell me all I wanted to know; so I knocked at the door, and made up my mind I wouldn't forget I was a girl. + CHAPTER XI. + "COME in," says the woman, and I did. + She says: "Take a cheer." + I done it. + She looked me all over with her little shiny eyes, and says: + "What might your name be?" + "Sarah Williams." + "Where 'bouts do you live? + In this neighborhood?' + "No'm. + In Hookerville, seven mile below. + I've walked all the way and I'm all tired out." + "Hungry, too, I reckon. + I'll find you something." + "No'm, I ain't hungry. + I was so hungry I had to stop two miles below here at a farm; so I ain't hungry no more. + It's what makes me so late. + My mother's down sick, and out of money and everything, and I come to tell my uncle Abner Moore. + He lives at the upper end of the town, she says. + I hain't ever been here before. + Do you know him?" + "No; but I don't know everybody yet. + I haven't lived here quite two weeks. + It's a considerable ways to the upper end of the town. + You better stay here all night. + Take off your bonnet." + "No," I says; "I'll rest a while, I reckon, and go on. + I ain't afeared of the dark." + She said she wouldn't let me go by myself, but her husband would be in by and by, maybe in a hour and a half, and she'd send him along with me. + Then she got to talking about her husband, and about her relations up the river, and her relations down the river, and about how much better off they used to was, and how they didn't know but they'd made a mistake coming to our town, instead of letting well alone—and so on and so on, till I was afeard I had made a mistake coming to her to find out what was going on in the town; but by and by she dropped on to pap and the murder, and then I was pretty willing to let her clatter right along. + She told about me and Tom Sawyer finding the six thousand dollars (only she got it ten) and all about pap and what a hard lot he was, and what a hard lot I was, and at last she got down to where I was murdered. + I says: + "Who done it? + We've heard considerable about these goings on down in Hookerville, but we don't know who 'twas that killed Huck Finn." + "Well, I reckon there's a right smart chance of people _here_ that'd like to know who killed him. + Some think old Finn done it himself." + "No—is that so?" + "Most everybody thought it at first. + He'll never know how nigh he come to getting lynched. + But before night they changed around and judged it was done by a runaway nigger named Jim." + "Why _he_—" + I stopped. + I reckoned I better keep still. + She run on, and never noticed I had put in at all: + "The nigger run off the very night Huck Finn was killed. + So there's a reward out for him—three hundred dollars. + And there's a reward out for old Finn, too—two hundred dollars. + You see, he come to town the morning after the murder, and told about it, and was out with 'em on the ferryboat hunt, and right away after he up and left. + Before night they wanted to lynch him, but he was gone, you see. + Well, next day they found out the nigger was gone; they found out he hadn't ben seen sence ten o'clock the night the murder was done. + So then they put it on him, you see; and while they was full of it, next day, back comes old Finn, and went boo-hooing to Judge Thatcher to get money to hunt for the nigger all over Illinois with. + The judge gave him some, and that evening he got drunk, and was around till after midnight with a couple of mighty hard-looking strangers, and then went off with them. + Well, he hain't come back sence, and they ain't looking for him back till this thing blows over a little, for people thinks now that he killed his boy and fixed things so folks would think robbers done it, and then he'd get Huck's money without having to bother a long time with a lawsuit. + People do say he warn't any too good to do it. + Oh, he's sly, I reckon. + If he don't come back for a year he'll be all right. + You can't prove anything on him, you know; everything will be quieted down then, and he'll walk in Huck's money as easy as nothing." + "Yes, I reckon so, 'm. + I don't see nothing in the way of it. + Has everybody quit thinking the nigger done it?" + "Oh, no, not everybody. + A good many thinks he done it. + But they'll get the nigger pretty soon now, and maybe they can scare it out of him." + "Why, are they after him yet?" + "Well, you're innocent, ain't you! + Does three hundred dollars lay around every day for people to pick up? + Some folks think the nigger ain't far from here. + I'm one of them—but I hain't talked it around. + A few days ago I was talking with an old couple that lives next door in the log shanty, and they happened to say hardly anybody ever goes to that island over yonder that they call Jackson's Island. + Don't anybody live there? + says I. No, nobody, says they. + I didn't say any more, but I done some thinking. + I was pretty near certain I'd seen smoke over there, about the head of the island, a day or two before that, so I says to myself, like as not that nigger's hiding over there; anyway, says I, it's worth the trouble to give the place a hunt. + I hain't seen any smoke sence, so I reckon maybe he's gone, if it was him; but husband's going over to see—him and another man. + He was gone up the river; but he got back to-day, and I told him as soon as he got here two hours ago." + I had got so uneasy I couldn't set still. + I had to do something with my hands; so I took up a needle off of the table and went to threading it. + My hands shook, and I was making a bad job of it. + When the woman stopped talking I looked up, and she was looking at me pretty curious and smiling a little. + I put down the needle and thread, and let on to be interested—and I was, too—and says: + "Three hundred dollars is a power of money. + I wish my mother could get it. + Is your husband going over there to-night?" + "Oh, yes. + He went up-town with the man I was telling you of, to get a boat and see if they could borrow another gun. + They'll go over after midnight." + "Couldn't they see better if they was to wait till daytime?" + "Yes. + And couldn't the nigger see better, too? + After midnight he'll likely be asleep, and they can slip around through the woods and hunt up his camp fire all the better for the dark, if he's got one." + "I didn't think of that." + The woman kept looking at me pretty curious, and I didn't feel a bit comfortable. + Pretty soon she says, + "What did you say your name was, honey?" + "M—Mary Williams." + Somehow it didn't seem to me that I said it was Mary before, so I didn't look up—seemed to me I said it was Sarah; so I felt sort of cornered, and was afeared maybe I was looking it, too. + I wished the woman would say something more; the longer she set still the uneasier I was. + But now she says: + "Honey, I thought you said it was Sarah when you first come in?" + "Oh, yes'm, I did. + Sarah Mary Williams. + Sarah's my first name. + Some calls me Sarah, some calls me Mary." + "Oh, that's the way of it?" + "Yes'm." + I was feeling better then, but I wished I was out of there, anyway. + I couldn't look up yet. + Well, the woman fell to talking about how hard times was, and how poor they had to live, and how the rats was as free as if they owned the place, and so forth and so on, and then I got easy again. + She was right about the rats. + You'd see one stick his nose out of a hole in the corner every little while. + She said she had to have things handy to throw at them when she was alone, or they wouldn't give her no peace. + She showed me a bar of lead twisted up into a knot, and said she was a good shot with it generly, but she'd wrenched her arm a day or two ago, and didn't know whether she could throw true now. + But she watched for a chance, and directly banged away at a rat; but she missed him wide, and said "Ouch!" + it hurt her arm so. + Then she told me to try for the next one. + I wanted to be getting away before the old man got back, but of course I didn't let on. + I got the thing, and the first rat that showed his nose I let drive, and if he'd a stayed where he was he'd a been a tolerable sick rat. + She said that was first-rate, and she reckoned I would hive the next one. + She went and got the lump of lead and fetched it back, and brought along a hank of yarn which she wanted me to help her with. + I held up my two hands and she put the hank over them, and went on talking about her and her husband's matters. + But she broke off to say: + "Keep your eye on the rats. + You better have the lead in your lap, handy." + So she dropped the lump into my lap just at that moment, and I clapped my legs together on it and she went on talking. + But only about a minute. + Then she took off the hank and looked me straight in the face, and very pleasant, and says: + "Come, now, what's your real name?" + "Wh—what, mum?" + "What's your real name? + Is it Bill, or Tom, or Bob? + —or what is it?" + I reckon I shook like a leaf, and I didn't know hardly what to do. + But I says: + "Please to don't poke fun at a poor girl like me, mum. + If I'm in the way here, I'll—" + "No, you won't. + Set down and stay where you are. + I ain't going to hurt you, and I ain't going to tell on you, nuther. + You just tell me your secret, and trust me. + I'll keep it; and, what's more, I'll help you. + So'll my old man if you want him to. + You see, you're a runaway 'prentice, that's all. + It ain't anything. + There ain't no harm in it. + You've been treated bad, and you made up your mind to cut. + Bless you, child, I wouldn't tell on you. + Tell me all about it now, that's a good boy." + So I said it wouldn't be no use to try to play it any longer, and I would just make a clean breast and tell her everything, but she musn't go back on her promise. + Then I told her my father and mother was dead, and the law had bound me out to a mean old farmer in the country thirty mile back from the river, and he treated me so bad I couldn't stand it no longer; he went away to be gone a couple of days, and so I took my chance and stole some of his daughter's old clothes and cleared out, and I had been three nights coming the thirty miles. + I traveled nights, and hid daytimes and slept, and the bag of bread and meat I carried from home lasted me all the way, and I had a-plenty. + I said I believed my uncle Abner Moore would take care of me, and so that was why I struck out for this town of Goshen. + "Goshen, child? + This ain't Goshen. + This is St. Petersburg. + Goshen's ten mile further up the river. + Who told you this was Goshen?" + "Why, a man I met at daybreak this morning, just as I was going to turn into the woods for my regular sleep. + He told me when the roads forked I must take the right hand, and five mile would fetch me to Goshen." + "He was drunk, I reckon. + He told you just exactly wrong." + "Well, he did act like he was drunk, but it ain't no matter now. + I got to be moving along. + I'll fetch Goshen before daylight." + "Hold on a minute. + I'll put you up a snack to eat. + You might want it." + So she put me up a snack, and says: + "Say, when a cow's laying down, which end of her gets up first? + Answer up prompt now—don't stop to study over it. + Which end gets up first?" + "The hind end, mum." + "Well, then, a horse?" + "The for'rard end, mum." + "Which side of a tree does the moss grow on?" + "North side." + "If fifteen cows is browsing on a hillside, how many of them eats with their heads pointed the same direction?" + "The whole fifteen, mum." + "Well, I reckon you _have_ lived in the country. + I thought maybe you was trying to hocus me again. + What's your real name, now?" + "George Peters, mum." + "Well, try to remember it, George. + Don't forget and tell me it's Elexander before you go, and then get out by saying it's George Elexander when I catch you. + And don't go about women in that old calico. + You do a girl tolerable poor, but you might fool men, maybe. + Bless you, child, when you set out to thread a needle don't hold the thread still and fetch the needle up to it; hold the needle still and poke the thread at it; that's the way a woman most always does, but a man always does t'other way. + And when you throw at a rat or anything, hitch yourself up a tiptoe and fetch your hand up over your head as awkward as you can, and miss your rat about six or seven foot. + Throw stiff-armed from the shoulder, like there was a pivot there for it to turn on, like a girl; not from the wrist and elbow, with your arm out to one side, like a boy. + And, mind you, when a girl tries to catch anything in her lap she throws her knees apart; she don't clap them together, the way you did when you catched the lump of lead. + Why, I spotted you for a boy when you was threading the needle; and I contrived the other things just to make certain. + Now trot along to your uncle, Sarah Mary Williams George Elexander Peters, and if you get into trouble you send word to Mrs. Judith Loftus, which is me, and I'll do what I can to get you out of it. + Keep the river road all the way, and next time you tramp take shoes and socks with you. + The river road's a rocky one, and your feet'll be in a condition when you get to Goshen, I reckon." + I went up the bank about fifty yards, and then I doubled on my tracks and slipped back to where my canoe was, a good piece below the house. + I jumped in, and was off in a hurry. + I went up-stream far enough to make the head of the island, and then started across. + I took off the sun-bonnet, for I didn't want no blinders on then. + When I was about the middle I heard the clock begin to strike, so I stops and listens; the sound come faint over the water but clear—eleven. + When I struck the head of the island I never waited to blow, though I was most winded, but I shoved right into the timber where my old camp used to be, and started a good fire there on a high and dry spot. + Then I jumped in the canoe and dug out for our place, a mile and a half below, as hard as I could go. + I landed, and slopped through the timber and up the ridge and into the cavern. + There Jim laid, sound asleep on the ground. + I roused him out and says: + "Git up and hump yourself, Jim! + There ain't a minute to lose. + They're after us!" + Jim never asked no questions, he never said a word; but the way he worked for the next half an hour showed about how he was scared. + By that time everything we had in the world was on our raft, and she was ready to be shoved out from the willow cove where she was hid. + We put out the camp fire at the cavern the first thing, and didn't show a candle outside after that. + I took the canoe out from the shore a little piece, and took a look; but if there was a boat around I couldn't see it, for stars and shadows ain't good to see by. + Then we got out the raft and slipped along down in the shade, past the foot of the island dead still—never saying a word. + CHAPTER XII. + IT must a been close on to one o'clock when we got below the island at last, and the raft did seem to go mighty slow. + If a boat was to come along we was going to take to the canoe and break for the Illinois shore; and it was well a boat didn't come, for we hadn't ever thought to put the gun in the canoe, or a fishing-line, or anything to eat. + We was in ruther too much of a sweat to think of so many things. + It warn't good judgment to put _everything_ on the raft. + If the men went to the island I just expect they found the camp fire I built, and watched it all night for Jim to come. + Anyways, they stayed away from us, and if my building the fire never fooled them it warn't no fault of mine. + I played it as low down on them as I could. + When the first streak of day began to show we tied up to a towhead in a big bend on the Illinois side, and hacked off cottonwood branches with the hatchet, and covered up the raft with them so she looked like there had been a cave-in in the bank there. + A tow-head is a sandbar that has cottonwoods on it as thick as harrow-teeth. + We had mountains on the Missouri shore and heavy timber on the Illinois side, and the channel was down the Missouri shore at that place, so we warn't afraid of anybody running across us. + We laid there all day, and watched the rafts and steamboats spin down the Missouri shore, and up-bound steamboats fight the big river in the middle. + I told Jim all about the time I had jabbering with that woman; and Jim said she was a smart one, and if she was to start after us herself she wouldn't set down and watch a camp fire—no, sir, she'd fetch a dog. + Well, then, I said, why couldn't she tell her husband to fetch a dog? + Jim said he bet she did think of it by the time the men was ready to start, and he believed they must a gone up-town to get a dog and so they lost all that time, or else we wouldn't be here on a towhead sixteen or seventeen mile below the village—no, indeedy, we would be in that same old town again. + So I said I didn't care what was the reason they didn't get us as long as they didn't. + When it was beginning to come on dark we poked our heads out of the cottonwood thicket, and looked up and down and across; nothing in sight; so Jim took up some of the top planks of the raft and built a snug wigwam to get under in blazing weather and rainy, and to keep the things dry. + Jim made a floor for the wigwam, and raised it a foot or more above the level of the raft, so now the blankets and all the traps was out of reach of steamboat waves. + Right in the middle of the wigwam we made a layer of dirt about five or six inches deep with a frame around it for to hold it to its place; this was to build a fire on in sloppy weather or chilly; the wigwam would keep it from being seen. + We made an extra steering-oar, too, because one of the others might get broke on a snag or something. + We fixed up a short forked stick to hang the old lantern on, because we must always light the lantern whenever we see a steamboat coming down-stream, to keep from getting run over; but we wouldn't have to light it for up-stream boats unless we see we was in what they call a "crossing"; for the river was pretty high yet, very low banks being still a little under water; so up-bound boats didn't always run the channel, but hunted easy water. + This second night we run between seven and eight hours, with a current that was making over four mile an hour. + We catched fish and talked, and we took a swim now and then to keep off sleepiness. + It was kind of solemn, drifting down the big, still river, laying on our backs looking up at the stars, and we didn't ever feel like talking loud, and it warn't often that we laughed—only a little kind of a low chuckle. + We had mighty good weather as a general thing, and nothing ever happened to us at all—that night, nor the next, nor the next. + Every night we passed towns, some of them away up on black hillsides, nothing but just a shiny bed of lights; not a house could you see. + The fifth night we passed St. Louis, and it was like the whole world lit up. + In St. Petersburg they used to say there was twenty or thirty thousand people in St. Louis, but I never believed it till I see that wonderful spread of lights at two o'clock that still night. + There warn't a sound there; everybody was asleep. + Every night now I used to slip ashore towards ten o'clock at some little village, and buy ten or fifteen cents' worth of meal or bacon or other stuff to eat; and sometimes I lifted a chicken that warn't roosting comfortable, and took him along. + Pap always said, take a chicken when you get a chance, because if you don't want him yourself you can easy find somebody that does, and a good deed ain't ever forgot. + I never see pap when he didn't want the chicken himself, but that is what he used to say, anyway. + Mornings before daylight I slipped into cornfields and borrowed a watermelon, or a mushmelon, or a punkin, or some new corn, or things of that kind. + Pap always said it warn't no harm to borrow things if you was meaning to pay them back some time; but the widow said it warn't anything but a soft name for stealing, and no decent body would do it. + Jim said he reckoned the widow was partly right and pap was partly right; so the best way would be for us to pick out two or three things from the list and say we wouldn't borrow them any more—then he reckoned it wouldn't be no harm to borrow the others. + So we talked it over all one night, drifting along down the river, trying to make up our minds whether to drop the watermelons, or the cantelopes, or the mushmelons, or what. + But towards daylight we got it all settled satisfactory, and concluded to drop crabapples and p'simmons. + We warn't feeling just right before that, but it was all comfortable now. + I was glad the way it come out, too, because crabapples ain't ever good, and the p'simmons wouldn't be ripe for two or three months yet. + We shot a water-fowl now and then that got up too early in the morning or didn't go to bed early enough in the evening. + Take it all round, we lived pretty high. + The fifth night below St. Louis we had a big storm after midnight, with a power of thunder and lightning, and the rain poured down in a solid sheet. + We stayed in the wigwam and let the raft take care of itself. + When the lightning glared out we could see a big straight river ahead, and high, rocky bluffs on both sides. + By and by says I, "Hel-_lo_, Jim, looky yonder!" + It was a steamboat that had killed herself on a rock. + We was drifting straight down for her. + The lightning showed her very distinct. + She was leaning over, with part of her upper deck above water, and you could see every little chimbly-guy clean and clear, and a chair by the big bell, with an old slouch hat hanging on the back of it, when the flashes come. + Well, it being away in the night and stormy, and all so mysterious-like, I felt just the way any other boy would a felt when I see that wreck laying there so mournful and lonesome in the middle of the river. + I wanted to get aboard of her and slink around a little, and see what there was there. + So I says: + "Le's land on her, Jim." + But Jim was dead against it at first. + He says: + "I doan' want to go fool'n 'long er no wrack. + We's doin' blame' well, en we better let blame' well alone, as de good book says. + Like as not dey's a watchman on dat wrack." + "Watchman your grandmother," I says; "there ain't nothing to watch but the texas and the pilot-house; and do you reckon anybody's going to resk his life for a texas and a pilot-house such a night as this, when it's likely to break up and wash off down the river any minute?" + Jim couldn't say nothing to that, so he didn't try. + "And besides," I says, "we might borrow something worth having out of the captain's stateroom. + Seegars, I bet you—and cost five cents apiece, solid cash. + Steamboat captains is always rich, and get sixty dollars a month, and _they_ don't care a cent what a thing costs, you know, long as they want it. + Stick a candle in your pocket; I can't rest, Jim, till we give her a rummaging. + Do you reckon Tom Sawyer would ever go by this thing? + Not for pie, he wouldn't. + He'd call it an adventure—that's what he'd call it; and he'd land on that wreck if it was his last act. + And wouldn't he throw style into it? + —wouldn't he spread himself, nor nothing? + Why, you'd think it was Christopher C'lumbus discovering Kingdom-Come. + I wish Tom Sawyer _was_ here." + Jim he grumbled a little, but give in. + He said we mustn't talk any more than we could help, and then talk mighty low. + The lightning showed us the wreck again just in time, and we fetched the stabboard derrick, and made fast there. + The deck was high out here. + We went sneaking down the slope of it to labboard, in the dark, towards the texas, feeling our way slow with our feet, and spreading our hands out to fend off the guys, for it was so dark we couldn't see no sign of them. + Pretty soon we struck the forward end of the skylight, and clumb on to it; and the next step fetched us in front of the captain's door, which was open, and by Jimminy, away down through the texas-hall we see a light! + and all in the same second we seem to hear low voices in yonder! + Jim whispered and said he was feeling powerful sick, and told me to come along. + I says, all right, and was going to start for the raft; but just then I heard a voice wail out and say: + "Oh, please don't, boys; I swear I won't ever tell!" + Another voice said, pretty loud: + "It's a lie, Jim Turner. + You've acted this way before. + You always want more'n your share of the truck, and you've always got it, too, because you've swore 't if you didn't you'd tell. + But this time you've said it jest one time too many. + You're the meanest, treacherousest hound in this country." + By this time Jim was gone for the raft. + I was just a-biling with curiosity; and I says to myself, Tom Sawyer wouldn't back out now, and so I won't either; I'm a-going to see what's going on here. + So I dropped on my hands and knees in the little passage, and crept aft in the dark till there warn't but one stateroom betwixt me and the cross-hall of the texas. + Then in there I see a man stretched on the floor and tied hand and foot, and two men standing over him, and one of them had a dim lantern in his hand, and the other one had a pistol. + This one kept pointing the pistol at the man's head on the floor, and saying: + "I'd _like_ to! + And I orter, too—a mean skunk!" + The man on the floor would shrivel up and say, "Oh, please don't, Bill; I hain't ever goin' to tell." + And every time he said that the man with the lantern would laugh and say: + "'Deed you _ain't! + _ You never said no truer thing 'n that, you bet you." + And once he said: "Hear him beg! + and yit if we hadn't got the best of him and tied him he'd a killed us both. + And what _for_? + Jist for noth'n. Jist because we stood on our _rights_—that's what for. + But I lay you ain't a-goin' to threaten nobody any more, Jim Turner. + Put _up_ that pistol, Bill." + Bill says: + "I don't want to, Jake Packard. + I'm for killin' him—and didn't he kill old Hatfield jist the same way—and don't he deserve it?" + "But I don't _want_ him killed, and I've got my reasons for it." + "Bless yo' heart for them words, Jake Packard! + I'll never forgit you long's I live!" + says the man on the floor, sort of blubbering. + Packard didn't take no notice of that, but hung up his lantern on a nail and started towards where I was there in the dark, and motioned Bill to come. + I crawfished as fast as I could about two yards, but the boat slanted so that I couldn't make very good time; so to keep from getting run over and catched I crawled into a stateroom on the upper side. + The man came a-pawing along in the dark, and when Packard got to my stateroom, he says: + "Here—come in here." + And in he come, and Bill after him. + But before they got in I was up in the upper berth, cornered, and sorry I come. + Then they stood there, with their hands on the ledge of the berth, and talked. + I couldn't see them, but I could tell where they was by the whisky they'd been having. + I was glad I didn't drink whisky; but it wouldn't made much difference anyway, because most of the time they couldn't a treed me because I didn't breathe. + I was too scared. + And, besides, a body _couldn't_ breathe and hear such talk. + They talked low and earnest. + Bill wanted to kill Turner. + He says: + "He's said he'll tell, and he will. + If we was to give both our shares to him _now_ it wouldn't make no difference after the row and the way we've served him. + Shore's you're born, he'll turn State's evidence; now you hear _me_. + I'm for putting him out of his troubles." + "So'm I," says Packard, very quiet. + "Blame it, I'd sorter begun to think you wasn't. + Well, then, that's all right. + Le's go and do it." + "Hold on a minute; I hain't had my say yit. + You listen to me. + Shooting's good, but there's quieter ways if the thing's _got_ to be done. + But what I say is this: it ain't good sense to go court'n around after a halter if you can git at what you're up to in some way that's jist as good and at the same time don't bring you into no resks. + Ain't that so?" + "You bet it is. + But how you goin' to manage it this time?" + "Well, my idea is this: we'll rustle around and gather up whatever pickins we've overlooked in the staterooms, and shove for shore and hide the truck. + Then we'll wait. + Now I say it ain't a-goin' to be more'n two hours befo' this wrack breaks up and washes off down the river. + See? + He'll be drownded, and won't have nobody to blame for it but his own self. + I reckon that's a considerble sight better 'n killin' of him. + I'm unfavorable to killin' a man as long as you can git aroun' it; it ain't good sense, it ain't good morals. + Ain't I right?" + "Yes, I reck'n you are. + But s'pose she _don't_ break up and wash off?" + "Well, we can wait the two hours anyway and see, can't we?" + "All right, then; come along." + So they started, and I lit out, all in a cold sweat, and scrambled forward. + It was dark as pitch there; but I said, in a kind of a coarse whisper, "Jim!" + and he answered up, right at my elbow, with a sort of a moan, and I says: + "Quick, Jim, it ain't no time for fooling around and moaning; there's a gang of murderers in yonder, and if we don't hunt up their boat and set her drifting down the river so these fellows can't get away from the wreck there's one of 'em going to be in a bad fix. + But if we find their boat we can put _all_ of 'em in a bad fix—for the sheriff 'll get 'em. + Quick—hurry! + I'll hunt the labboard side, you hunt the stabboard. + You start at the raft, and—" + "Oh, my lordy, lordy! + _raf'_? + Dey ain' no raf' no mo'; she done broke loose en gone I—en here we is!" + CHAPTER XIII. + WELL, I catched my breath and most fainted. + Shut up on a wreck with such a gang as that! + But it warn't no time to be sentimentering. + We'd _got_ to find that boat now—had to have it for ourselves. + So we went a-quaking and shaking down the stabboard side, and slow work it was, too—seemed a week before we got to the stern. + No sign of a boat. + Jim said he didn't believe he could go any further—so scared he hadn't hardly any strength left, he said. + But I said, come on, if we get left on this wreck we are in a fix, sure. + So on we prowled again. + We struck for the stern of the texas, and found it, and then scrabbled along forwards on the skylight, hanging on from shutter to shutter, for the edge of the skylight was in the water. + When we got pretty close to the cross-hall door there was the skiff, sure enough! + I could just barely see her. + I felt ever so thankful. + In another second I would a been aboard of her, but just then the door opened. + One of the men stuck his head out only about a couple of foot from me, and I thought I was gone; but he jerked it in again, and says: + "Heave that blame lantern out o' sight, Bill!" + He flung a bag of something into the boat, and then got in himself and set down. + It was Packard. + Then Bill _he_ come out and got in. + Packard says, in a low voice: + "All ready—shove off!" + I couldn't hardly hang on to the shutters, I was so weak. + But Bill says: + "Hold on—'d you go through him?" + "No. + Didn't you?" + "No. + So he's got his share o' the cash yet." + "Well, then, come along; no use to take truck and leave money." + "Say, won't he suspicion what we're up to?" + "Maybe he won't. + But we got to have it anyway. + Come along." + So they got out and went in. + The door slammed to because it was on the careened side; and in a half second I was in the boat, and Jim come tumbling after me. + I out with my knife and cut the rope, and away we went! + We didn't touch an oar, and we didn't speak nor whisper, nor hardly even breathe. + We went gliding swift along, dead silent, past the tip of the paddle-box, and past the stern; then in a second or two more we was a hundred yards below the wreck, and the darkness soaked her up, every last sign of her, and we was safe, and knowed it. + When we was three or four hundred yards down-stream we see the lantern show like a little spark at the texas door for a second, and we knowed by that that the rascals had missed their boat, and was beginning to understand that they was in just as much trouble now as Jim Turner was. + Then Jim manned the oars, and we took out after our raft. + Now was the first time that I begun to worry about the men—I reckon I hadn't had time to before. + I begun to think how dreadful it was, even for murderers, to be in such a fix. + I says to myself, there ain't no telling but I might come to be a murderer myself yet, and then how would I like it? + So says I to Jim: + "The first light we see we'll land a hundred yards below it or above it, in a place where it's a good hiding-place for you and the skiff, and then I'll go and fix up some kind of a yarn, and get somebody to go for that gang and get them out of their scrape, so they can be hung when their time comes." + But that idea was a failure; for pretty soon it begun to storm again, and this time worse than ever. + The rain poured down, and never a light showed; everybody in bed, I reckon. + We boomed along down the river, watching for lights and watching for our raft. + After a long time the rain let up, but the clouds stayed, and the lightning kept whimpering, and by and by a flash showed us a black thing ahead, floating, and we made for it. + It was the raft, and mighty glad was we to get aboard of it again. + We seen a light now away down to the right, on shore. + So I said I would go for it. + The skiff was half full of plunder which that gang had stole there on the wreck. + We hustled it on to the raft in a pile, and I told Jim to float along down, and show a light when he judged he had gone about two mile, and keep it burning till I come; then I manned my oars and shoved for the light. + As I got down towards it three or four more showed—up on a hillside. + It was a village. + I closed in above the shore light, and laid on my oars and floated. + As I went by I see it was a lantern hanging on the jackstaff of a double-hull ferryboat. + I skimmed around for the watchman, a-wondering whereabouts he slept; and by and by I found him roosting on the bitts forward, with his head down between his knees. + I gave his shoulder two or three little shoves, and begun to cry. + He stirred up in a kind of a startlish way; but when he see it was only me he took a good gap and stretch, and then he says: + "Hello, what's up? + Don't cry, bub. + What's the trouble?" + I says: + "Pap, and mam, and sis, and—" + Then I broke down. + He says: + "Oh, dang it now, _don't_ take on so; we all has to have our troubles, and this 'n 'll come out all right. + What's the matter with 'em?" + "They're—they're—are you the watchman of the boat?" + "Yes," he says, kind of pretty-well-satisfied like. + "I'm the captain and the owner and the mate and the pilot and watchman and head deck-hand; and sometimes I'm the freight and passengers. + I ain't as rich as old Jim Hornback, and I can't be so blame' generous and good to Tom, Dick, and Harry as what he is, and slam around money the way he does; but I've told him a many a time 't I wouldn't trade places with him; for, says I, a sailor's life's the life for me, and I'm derned if _I'd_ live two mile out o' town, where there ain't nothing ever goin' on, not for all his spondulicks and as much more on top of it. + Says I—" + I broke in and says: + "They're in an awful peck of trouble, and—" + "_Who_ is?" + "Why, pap and mam and sis and Miss Hooker; and if you'd take your ferryboat and go up there—" + "Up where? + Where are they?" + "On the wreck." + "What wreck?" + "Why, there ain't but one." + "What, you don't mean the Walter Scott?" + "Yes." + "Good land! + what are they doin' _there_, for gracious sakes?" + "Well, they didn't go there a-purpose." + "I bet they didn't! + Why, great goodness, there ain't no chance for 'em if they don't git off mighty quick! + Why, how in the nation did they ever git into such a scrape?" + "Easy enough. + Miss Hooker was a-visiting up there to the town—" + "Yes, Booth's Landing—go on." + "She was a-visiting there at Booth's Landing, and just in the edge of the evening she started over with her nigger woman in the horse-ferry to stay all night at her friend's house, Miss What-you-may-call-her I disremember her name—and they lost their steering-oar, and swung around and went a-floating down, stern first, about two mile, and saddle-baggsed on the wreck, and the ferryman and the nigger woman and the horses was all lost, but Miss Hooker she made a grab and got aboard the wreck. + Well, about an hour after dark we come along down in our trading-scow, and it was so dark we didn't notice the wreck till we was right on it; and so _we_ saddle-baggsed; but all of us was saved but Bill Whipple—and oh, he _was_ the best cretur! + —I most wish 't it had been me, I do." + "My George! + It's the beatenest thing I ever struck. + And _then_ what did you all do?" + "Well, we hollered and took on, but it's so wide there we couldn't make nobody hear. + So pap said somebody got to get ashore and get help somehow. + I was the only one that could swim, so I made a dash for it, and Miss Hooker she said if I didn't strike help sooner, come here and hunt up her uncle, and he'd fix the thing. + I made the land about a mile below, and been fooling along ever since, trying to get people to do something, but they said, 'What, in such a night and such a current? + There ain't no sense in it; go for the steam ferry.' + Now if you'll go and—" + "By Jackson, I'd _like_ to, and, blame it, I don't know but I will; but who in the dingnation's a-going' to _pay_ for it? + Do you reckon your pap—" + "Why _that's_ all right. + Miss Hooker she tole me, _particular_, that her uncle Hornback—" + "Great guns! + is _he_ her uncle? + Looky here, you break for that light over yonder-way, and turn out west when you git there, and about a quarter of a mile out you'll come to the tavern; tell 'em to dart you out to Jim Hornback's, and he'll foot the bill. + And don't you fool around any, because he'll want to know the news. + Tell him I'll have his niece all safe before he can get to town. + Hump yourself, now; I'm a-going up around the corner here to roust out my engineer." + I struck for the light, but as soon as he turned the corner I went back and got into my skiff and bailed her out, and then pulled up shore in the easy water about six hundred yards, and tucked myself in among some woodboats; for I couldn't rest easy till I could see the ferryboat start. + But take it all around, I was feeling ruther comfortable on accounts of taking all this trouble for that gang, for not many would a done it. + I wished the widow knowed about it. + I judged she would be proud of me for helping these rapscallions, because rapscallions and dead beats is the kind the widow and good people takes the most interest in. + Well, before long here comes the wreck, dim and dusky, sliding along down! + A kind of cold shiver went through me, and then I struck out for her. + She was very deep, and I see in a minute there warn't much chance for anybody being alive in her. + I pulled all around her and hollered a little, but there wasn't any answer; all dead still. + I felt a little bit heavy-hearted about the gang, but not much, for I reckoned if they could stand it I could. + Then here comes the ferryboat; so I shoved for the middle of the river on a long down-stream slant; and when I judged I was out of eye-reach I laid on my oars, and looked back and see her go and smell around the wreck for Miss Hooker's remainders, because the captain would know her uncle Hornback would want them; and then pretty soon the ferryboat give it up and went for the shore, and I laid into my work and went a-booming down the river. + It did seem a powerful long time before Jim's light showed up; and when it did show it looked like it was a thousand mile off. + By the time I got there the sky was beginning to get a little gray in the east; so we struck for an island, and hid the raft, and sunk the skiff, and turned in and slept like dead people. + CHAPTER XIV. + BY and by, when we got up, we turned over the truck the gang had stole off of the wreck, and found boots, and blankets, and clothes, and all sorts of other things, and a lot of books, and a spyglass, and three boxes of seegars. + We hadn't ever been this rich before in neither of our lives. + The seegars was prime. + We laid off all the afternoon in the woods talking, and me reading the books, and having a general good time. + I told Jim all about what happened inside the wreck and at the ferryboat, and I said these kinds of things was adventures; but he said he didn't want no more adventures. + He said that when I went in the texas and he crawled back to get on the raft and found her gone he nearly died, because he judged it was all up with _him_ anyway it could be fixed; for if he didn't get saved he would get drownded; and if he did get saved, whoever saved him would send him back home so as to get the reward, and then Miss Watson would sell him South, sure. + Well, he was right; he was most always right; he had an uncommon level head for a nigger. + I read considerable to Jim about kings and dukes and earls and such, and how gaudy they dressed, and how much style they put on, and called each other your majesty, and your grace, and your lordship, and so on, 'stead of mister; and Jim's eyes bugged out, and he was interested. + He says: + "I didn' know dey was so many un um. + I hain't hearn 'bout none un um, skasely, but ole King Sollermun, onless you counts dem kings dat's in a pack er k'yards. + How much do a king git?" + "Get?" + I says; "why, they get a thousand dollars a month if they want it; they can have just as much as they want; everything belongs to them." + "_Ain'_ dat gay? + En what dey got to do, Huck?" + "_They_ don't do nothing! + Why, how you talk! + They just set around." + "No; is dat so?" + "Of course it is. + They just set around—except, maybe, when there's a war; then they go to the war. + But other times they just lazy around; or go hawking—just hawking and sp—Sh! + —d' you hear a noise?" + We skipped out and looked; but it warn't nothing but the flutter of a steamboat's wheel away down, coming around the point; so we come back. + "Yes," says I, "and other times, when things is dull, they fuss with the parlyment; and if everybody don't go just so he whacks their heads off. + But mostly they hang round the harem." + "Roun' de which?" + "Harem." + "What's de harem?" + "The place where he keeps his wives. + Don't you know about the harem? + Solomon had one; he had about a million wives." + "Why, yes, dat's so; I—I'd done forgot it. + A harem's a bo'd'n-house, I reck'n. Mos' likely dey has rackety times in de nussery. + En I reck'n de wives quarrels considable; en dat 'crease de racket. + Yit dey say Sollermun de wises' man dat ever live'. + I doan' take no stock in dat. + Bekase why: would a wise man want to live in de mids' er sich a blim-blammin' all de time? + No—'deed he wouldn't. + A wise man 'ud take en buil' a biler-factry; en den he could shet _down_ de biler-factry when he want to res'." + "Well, but he _was_ the wisest man, anyway; because the widow she told me so, her own self." + "I doan k'yer what de widder say, he _warn't_ no wise man nuther. + He had some er de dad-fetchedes' ways I ever see. + Does you know 'bout dat chile dat he 'uz gwyne to chop in two?" + "Yes, the widow told me all about it." + "_Well_, den! + Warn' dat de beatenes' notion in de worl'? + You jes' take en look at it a minute. + Dah's de stump, dah—dat's one er de women; heah's you—dat's de yuther one; I's Sollermun; en dish yer dollar bill's de chile. + Bofe un you claims it. + What does I do? + Does I shin aroun' mongs' de neighbors en fine out which un you de bill _do_ b'long to, en han' it over to de right one, all safe en soun', de way dat anybody dat had any gumption would? + No; I take en whack de bill in _two_, en give half un it to you, en de yuther half to de yuther woman. + Dat's de way Sollermun was gwyne to do wid de chile. + Now I want to ast you: what's de use er dat half a bill? + —can't buy noth'n wid it. + En what use is a half a chile? + I wouldn' give a dern for a million un um." + "But hang it, Jim, you've clean missed the point—blame it, you've missed it a thousand mile." + "Who? + Me? + Go 'long. + Doan' talk to me 'bout yo' pints. + I reck'n I knows sense when I sees it; en dey ain' no sense in sich doin's as dat. + De 'spute warn't 'bout a half a chile, de 'spute was 'bout a whole chile; en de man dat think he kin settle a 'spute 'bout a whole chile wid a half a chile doan' know enough to come in out'n de rain. + Doan' talk to me 'bout Sollermun, Huck, I knows him by de back." + "But I tell you you don't get the point." + "Blame de point! + I reck'n I knows what I knows. + En mine you, de _real_ pint is down furder—it's down deeper. + It lays in de way Sollermun was raised. + You take a man dat's got on'y one or two chillen; is dat man gwyne to be waseful o' chillen? + No, he ain't; he can't 'ford it. + _He_ know how to value 'em. + But you take a man dat's got 'bout five million chillen runnin' roun' de house, en it's diffunt. + _He_ as soon chop a chile in two as a cat. + Dey's plenty mo'. + A chile er two, mo' er less, warn't no consekens to Sollermun, dad fatch him!" + I never see such a nigger. + If he got a notion in his head once, there warn't no getting it out again. + He was the most down on Solomon of any nigger I ever see. + So I went to talking about other kings, and let Solomon slide. + I told about Louis Sixteenth that got his head cut off in France long time ago; and about his little boy the dolphin, that would a been a king, but they took and shut him up in jail, and some say he died there. + "Po' little chap." + "But some says he got out and got away, and come to America." + "Dat's good! + But he'll be pooty lonesome—dey ain' no kings here, is dey, Huck?" + "No." + "Den he cain't git no situation. + What he gwyne to do?" + "Well, I don't know. + Some of them gets on the police, and some of them learns people how to talk French." + "Why, Huck, doan' de French people talk de same way we does?" + "_No_, Jim; you couldn't understand a word they said—not a single word." + "Well, now, I be ding-busted! + How do dat come?" + "I don't know; but it's so. + I got some of their jabber out of a book. + S'pose a man was to come to you and say Polly-voo-franzy—what would you think?" + "I wouldn' think nuff'n; I'd take en bust him over de head—dat is, if he warn't white. + I wouldn't 'low no nigger to call me dat." + "Shucks, it ain't calling you anything. + It's only saying, do you know how to talk French?" + "Well, den, why couldn't he _say_ it?" + "Why, he _is_ a-saying it. + That's a Frenchman's _way_ of saying it." + "Well, it's a blame ridicklous way, en I doan' want to hear no mo' 'bout it. + Dey ain' no sense in it." + "Looky here, Jim; does a cat talk like we do?" + "No, a cat don't." + "Well, does a cow?" + "No, a cow don't, nuther." + "Does a cat talk like a cow, or a cow talk like a cat?" + "No, dey don't." + "It's natural and right for 'em to talk different from each other, ain't it?" + "Course." + "And ain't it natural and right for a cat and a cow to talk different from _us_?" + "Why, mos' sholy it is." + "Well, then, why ain't it natural and right for a _Frenchman_ to talk different from us? + You answer me that." + "Is a cat a man, Huck?" + "No." + "Well, den, dey ain't no sense in a cat talkin' like a man. + Is a cow a man? + —er is a cow a cat?" + "No, she ain't either of them." + "Well, den, she ain't got no business to talk like either one er the yuther of 'em. + Is a Frenchman a man?" + "Yes." + "_Well_, den! + Dad blame it, why doan' he _talk_ like a man? + You answer me _dat_!" + I see it warn't no use wasting words—you can't learn a nigger to argue. + So I quit. + CHAPTER XV. + WE judged that three nights more would fetch us to Cairo, at the bottom of Illinois, where the Ohio River comes in, and that was what we was after. + We would sell the raft and get on a steamboat and go way up the Ohio amongst the free States, and then be out of trouble. + Well, the second night a fog begun to come on, and we made for a towhead to tie to, for it wouldn't do to try to run in a fog; but when I paddled ahead in the canoe, with the line to make fast, there warn't anything but little saplings to tie to. + I passed the line around one of them right on the edge of the cut bank, but there was a stiff current, and the raft come booming down so lively she tore it out by the roots and away she went. + I see the fog closing down, and it made me so sick and scared I couldn't budge for most a half a minute it seemed to me—and then there warn't no raft in sight; you couldn't see twenty yards. + I jumped into the canoe and run back to the stern, and grabbed the paddle and set her back a stroke. + But she didn't come. + I was in such a hurry I hadn't untied her. + I got up and tried to untie her, but I was so excited my hands shook so I couldn't hardly do anything with them. + As soon as I got started I took out after the raft, hot and heavy, right down the towhead. + That was all right as far as it went, but the towhead warn't sixty yards long, and the minute I flew by the foot of it I shot out into the solid white fog, and hadn't no more idea which way I was going than a dead man. + Thinks I, it won't do to paddle; first I know I'll run into the bank or a towhead or something; I got to set still and float, and yet it's mighty fidgety business to have to hold your hands still at such a time. + I whooped and listened. + Away down there somewheres I hears a small whoop, and up comes my spirits. + I went tearing after it, listening sharp to hear it again. + The next time it come I see I warn't heading for it, but heading away to the right of it. + And the next time I was heading away to the left of it—and not gaining on it much either, for I was flying around, this way and that and t'other, but it was going straight ahead all the time. + I did wish the fool would think to beat a tin pan, and beat it all the time, but he never did, and it was the still places between the whoops that was making the trouble for me. + Well, I fought along, and directly I hears the whoop _behind_ me. + I was tangled good now. + That was somebody else's whoop, or else I was turned around. + I throwed the paddle down. + I heard the whoop again; it was behind me yet, but in a different place; it kept coming, and kept changing its place, and I kept answering, till by and by it was in front of me again, and I knowed the current had swung the canoe's head down-stream, and I was all right if that was Jim and not some other raftsman hollering. + I couldn't tell nothing about voices in a fog, for nothing don't look natural nor sound natural in a fog. + The whooping went on, and in about a minute I come a-booming down on a cut bank with smoky ghosts of big trees on it, and the current throwed me off to the left and shot by, amongst a lot of snags that fairly roared, the currrent was tearing by them so swift. + In another second or two it was solid white and still again. + I set perfectly still then, listening to my heart thump, and I reckon I didn't draw a breath while it thumped a hundred. + I just give up then. + I knowed what the matter was. + That cut bank was an island, and Jim had gone down t'other side of it. + It warn't no towhead that you could float by in ten minutes. + It had the big timber of a regular island; it might be five or six miles long and more than half a mile wide. + I kept quiet, with my ears cocked, about fifteen minutes, I reckon. + I was floating along, of course, four or five miles an hour; but you don't ever think of that. + No, you _feel_ like you are laying dead still on the water; and if a little glimpse of a snag slips by you don't think to yourself how fast _you're_ going, but you catch your breath and think, my! + how that snag's tearing along. + If you think it ain't dismal and lonesome out in a fog that way by yourself in the night, you try it once—you'll see. + Next, for about a half an hour, I whoops now and then; at last I hears the answer a long ways off, and tries to follow it, but I couldn't do it, and directly I judged I'd got into a nest of towheads, for I had little dim glimpses of them on both sides of me—sometimes just a narrow channel between, and some that I couldn't see I knowed was there because I'd hear the wash of the current against the old dead brush and trash that hung over the banks. + Well, I warn't long loosing the whoops down amongst the towheads; and I only tried to chase them a little while, anyway, because it was worse than chasing a Jack-o'-lantern. + You never knowed a sound dodge around so, and swap places so quick and so much. + I had to claw away from the bank pretty lively four or five times, to keep from knocking the islands out of the river; and so I judged the raft must be butting into the bank every now and then, or else it would get further ahead and clear out of hearing—it was floating a little faster than what I was. + Well, I seemed to be in the open river again by and by, but I couldn't hear no sign of a whoop nowheres. + I reckoned Jim had fetched up on a snag, maybe, and it was all up with him. + I was good and tired, so I laid down in the canoe and said I wouldn't bother no more. + I didn't want to go to sleep, of course; but I was so sleepy I couldn't help it; so I thought I would take jest one little cat-nap. + But I reckon it was more than a cat-nap, for when I waked up the stars was shining bright, the fog was all gone, and I was spinning down a big bend stern first. + First I didn't know where I was; I thought I was dreaming; and when things began to come back to me they seemed to come up dim out of last week. + It was a monstrous big river here, with the tallest and the thickest kind of timber on both banks; just a solid wall, as well as I could see by the stars. + I looked away down-stream, and seen a black speck on the water. + I took after it; but when I got to it it warn't nothing but a couple of sawlogs made fast together. + Then I see another speck, and chased that; then another, and this time I was right. + It was the raft. + When I got to it Jim was setting there with his head down between his knees, asleep, with his right arm hanging over the steering-oar. + The other oar was smashed off, and the raft was littered up with leaves and branches and dirt. + So she'd had a rough time. + I made fast and laid down under Jim's nose on the raft, and began to gap, and stretch my fists out against Jim, and says: + "Hello, Jim, have I been asleep? + Why didn't you stir me up?" + "Goodness gracious, is dat you, Huck? + En you ain' dead—you ain' drownded—you's back agin? + It's too good for true, honey, it's too good for true. + Lemme look at you chile, lemme feel o' you. + No, you ain' dead! + you's back agin, 'live en soun', jis de same ole Huck—de same ole Huck, thanks to goodness!" + "What's the matter with you, Jim? + You been a-drinking?" + "Drinkin'? + Has I ben a-drinkin'? + Has I had a chance to be a-drinkin'?" + "Well, then, what makes you talk so wild?" + "How does I talk wild?" + "_How_? + Why, hain't you been talking about my coming back, and all that stuff, as if I'd been gone away?" + "Huck—Huck Finn, you look me in de eye; look me in de eye. + _Hain't_ you ben gone away?" + "Gone away? + Why, what in the nation do you mean? + I hain't been gone anywheres. + Where would I go to?" + "Well, looky here, boss, dey's sumf'n wrong, dey is. + Is I _me_, or who _is_ I? + Is I heah, or whah _is_ I? + Now dat's what I wants to know." + "Well, I think you're here, plain enough, but I think you're a tangle-headed old fool, Jim." + "I is, is I? + Well, you answer me dis: Didn't you tote out de line in de canoe fer to make fas' to de tow-head?" + "No, I didn't. + What tow-head? + I hain't see no tow-head." + "You hain't seen no towhead? + Looky here, didn't de line pull loose en de raf' go a-hummin' down de river, en leave you en de canoe behine in de fog?" + "What fog?" + "Why, de fog! + —de fog dat's been aroun' all night. + En didn't you whoop, en didn't I whoop, tell we got mix' up in de islands en one un us got los' en t'other one was jis' as good as los', 'kase he didn' know whah he wuz? + En didn't I bust up agin a lot er dem islands en have a turrible time en mos' git drownded? + Now ain' dat so, boss—ain't it so? + You answer me dat." + "Well, this is too many for me, Jim. + I hain't seen no fog, nor no islands, nor no troubles, nor nothing. + I been setting here talking with you all night till you went to sleep about ten minutes ago, and I reckon I done the same. + You couldn't a got drunk in that time, so of course you've been dreaming." + "Dad fetch it, how is I gwyne to dream all dat in ten minutes?" + "Well, hang it all, you did dream it, because there didn't any of it happen." + "But, Huck, it's all jis' as plain to me as—" + "It don't make no difference how plain it is; there ain't nothing in it. + I know, because I've been here all the time." + Jim didn't say nothing for about five minutes, but set there studying over it. + Then he says: + "Well, den, I reck'n I did dream it, Huck; but dog my cats ef it ain't de powerfullest dream I ever see. + En I hain't ever had no dream b'fo' dat's tired me like dis one." + "Oh, well, that's all right, because a dream does tire a body like everything sometimes. + But this one was a staving dream; tell me all about it, Jim." + So Jim went to work and told me the whole thing right through, just as it happened, only he painted it up considerable. + Then he said he must start in and "'terpret" it, because it was sent for a warning. + He said the first towhead stood for a man that would try to do us some good, but the current was another man that would get us away from him. + The whoops was warnings that would come to us every now and then, and if we didn't try hard to make out to understand them they'd just take us into bad luck, 'stead of keeping us out of it. + The lot of towheads was troubles we was going to get into with quarrelsome people and all kinds of mean folks, but if we minded our business and didn't talk back and aggravate them, we would pull through and get out of the fog and into the big clear river, which was the free States, and wouldn't have no more trouble. + It had clouded up pretty dark just after I got on to the raft, but it was clearing up again now. + "Oh, well, that's all interpreted well enough as far as it goes, Jim," I says; "but what does _these_ things stand for?" + It was the leaves and rubbish on the raft and the smashed oar. + You could see them first-rate now. + Jim looked at the trash, and then looked at me, and back at the trash again. + He had got the dream fixed so strong in his head that he couldn't seem to shake it loose and get the facts back into its place again right away. + But when he did get the thing straightened around he looked at me steady without ever smiling, and says: + "What do dey stan' for? + I'se gwyne to tell you. + When I got all wore out wid work, en wid de callin' for you, en went to sleep, my heart wuz mos' broke bekase you wuz los', en I didn' k'yer no' mo' what become er me en de raf'. + En when I wake up en fine you back agin, all safe en soun', de tears come, en I could a got down on my knees en kiss yo' foot, I's so thankful. + En all you wuz thinkin' 'bout wuz how you could make a fool uv ole Jim wid a lie. + Dat truck dah is _trash_; en trash is what people is dat puts dirt on de head er dey fren's en makes 'em ashamed." + Then he got up slow and walked to the wigwam, and went in there without saying anything but that. + But that was enough. + It made me feel so mean I could almost kissed _his_ foot to get him to take it back. + It was fifteen minutes before I could work myself up to go and humble myself to a nigger; but I done it, and I warn't ever sorry for it afterwards, neither. + I didn't do him no more mean tricks, and I wouldn't done that one if I'd a knowed it would make him feel that way. + + diff --git a/SelfSize/SelfSize/UYLTableViewController.h b/SelfSize/SelfSize/UYLTableViewController.h new file mode 100644 index 0000000..71f5f5f --- /dev/null +++ b/SelfSize/SelfSize/UYLTableViewController.h @@ -0,0 +1,38 @@ +// +// UYLTableViewController.h +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface UYLTableViewController : UITableViewController + +@end diff --git a/SelfSize/SelfSize/UYLTableViewController.m b/SelfSize/SelfSize/UYLTableViewController.m new file mode 100644 index 0000000..bb228da --- /dev/null +++ b/SelfSize/SelfSize/UYLTableViewController.m @@ -0,0 +1,115 @@ +// +// UYLTableViewController.m +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "UYLTableViewController.h" +#import "UYLTextCell.h" + +@interface UYLTableViewController () + +@property (nonatomic, strong) NSArray *sourceData; + +@end + +@implementation UYLTableViewController + +static NSString *UYLCellIdentifier = @"UYLTextCell"; + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +- (NSArray *)sourceData +{ + if (!_sourceData) + { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"SourceData" ofType:@"plist"]; + _sourceData = [NSArray arrayWithContentsOfFile:filePath]; + } + return _sourceData; +} + +#pragma mark - +#pragma mark === View Life Cycle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification object:nil]; + self.tableView.estimatedRowHeight = 100.0; + self.tableView.rowHeight = UITableViewAutomaticDimension; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIContentSizeCategoryDidChangeNotification + object:nil]; +} + +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self.tableView reloadData]; +} + +#pragma mark - +#pragma mark === UITableViewDataSource === +#pragma mark - + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.sourceData count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:UYLCellIdentifier forIndexPath:indexPath]; + [self configureCell:cell forRowAtIndexPath:indexPath]; + return cell; +} + +- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath +{ + if ([cell isKindOfClass:[UYLTextCell class]]) + { + UYLTextCell *textCell = (UYLTextCell *)cell; + textCell.numberLabel.text = [NSString stringWithFormat:@"Line %ld",(long)indexPath.row+1]; + textCell.numberLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; + textCell.lineLabel.text = [self.sourceData objectAtIndex:indexPath.row]; + textCell.lineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + } +} + +@end diff --git a/SelfSize/SelfSize/UYLTextCell.h b/SelfSize/SelfSize/UYLTextCell.h new file mode 100644 index 0000000..7d206f8 --- /dev/null +++ b/SelfSize/SelfSize/UYLTextCell.h @@ -0,0 +1,41 @@ +// +// UYLTextCell.h +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import + +@interface UYLTextCell : UITableViewCell + +@property (weak, nonatomic) IBOutlet UILabel *numberLabel; +@property (weak, nonatomic) IBOutlet UILabel *lineLabel; + +@end diff --git a/SelfSize/SelfSize/UYLTextCell.m b/SelfSize/SelfSize/UYLTextCell.m new file mode 100644 index 0000000..c14dbfe --- /dev/null +++ b/SelfSize/SelfSize/UYLTextCell.m @@ -0,0 +1,55 @@ +// +// UYLTextCell.m +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "UYLTextCell.h" + +@implementation UYLTextCell + +- (id)debugQuickLookObject +{ + NSAttributedString *cr = [[NSAttributedString alloc] initWithString:@"\n"]; + NSMutableAttributedString *result = [[NSMutableAttributedString alloc] initWithAttributedString:self.numberLabel.attributedText]; + [result appendAttributedString:cr]; + [result appendAttributedString:self.lineLabel.attributedText]; + return result; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + [self.contentView layoutIfNeeded]; + self.lineLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.lineLabel.frame); +} + +@end diff --git a/SelfSize/SelfSize/main.m b/SelfSize/SelfSize/main.m new file mode 100644 index 0000000..6c4b1c0 --- /dev/null +++ b/SelfSize/SelfSize/main.m @@ -0,0 +1,41 @@ +// +// main.m +// SelfSize +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/SpeakEasy/README b/SpeakEasy/README new file mode 100644 index 0000000..96d071a --- /dev/null +++ b/SpeakEasy/README @@ -0,0 +1,11 @@ +======================================================================= +SpeakEasy - Text to speech synthesis +Version 1.0 08 January 2013 Initial version. +======================================================================= + +Demonstration of the AVSpeechSynthesizer and related classes to perform +text to speech synthesis. Makes use of custom voices, pitch, rate and text +highlighting. + +For further details see the following blog post: +https://useyourloaf.com/blog/synthesized-speech-from-text/ diff --git a/SpeakEasy/SpeakEasy.xcodeproj/project.pbxproj b/SpeakEasy/SpeakEasy.xcodeproj/project.pbxproj new file mode 100644 index 0000000..07fa233 --- /dev/null +++ b/SpeakEasy/SpeakEasy.xcodeproj/project.pbxproj @@ -0,0 +1,351 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 530D9CF023C926AC0087DFA0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 530D9CEF23C926AC0087DFA0 /* LaunchScreen.storyboard */; }; + 5329C82318785C4F00B91692 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5329C82218785C4F00B91692 /* Foundation.framework */; }; + 5329C82518785C4F00B91692 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5329C82418785C4F00B91692 /* CoreGraphics.framework */; }; + 5329C82718785C4F00B91692 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5329C82618785C4F00B91692 /* UIKit.framework */; }; + 5329C82D18785C4F00B91692 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5329C82B18785C4F00B91692 /* InfoPlist.strings */; }; + 5329C82F18785C4F00B91692 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5329C82E18785C4F00B91692 /* main.m */; }; + 5329C83318785C4F00B91692 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5329C83218785C4F00B91692 /* UYLAppDelegate.m */; }; + 5329C83618785C4F00B91692 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5329C83418785C4F00B91692 /* Main.storyboard */; }; + 5329C83918785C4F00B91692 /* UYLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5329C83818785C4F00B91692 /* UYLViewController.m */; }; + 5329C83B18785C4F00B91692 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5329C83A18785C4F00B91692 /* Images.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 530D9CEF23C926AC0087DFA0 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 5329C81F18785C4F00B91692 /* SpeakEasy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpeakEasy.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5329C82218785C4F00B91692 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5329C82418785C4F00B91692 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5329C82618785C4F00B91692 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5329C82A18785C4F00B91692 /* SpeakEasy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SpeakEasy-Info.plist"; sourceTree = ""; }; + 5329C82C18785C4F00B91692 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 5329C82E18785C4F00B91692 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5329C83118785C4F00B91692 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; + 5329C83218785C4F00B91692 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; + 5329C83518785C4F00B91692 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5329C83718785C4F00B91692 /* UYLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLViewController.h; sourceTree = ""; }; + 5329C83818785C4F00B91692 /* UYLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLViewController.m; sourceTree = ""; }; + 5329C83A18785C4F00B91692 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 5329C84118785C4F00B91692 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 5386150B187DC41B00FA2AF9 /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5329C81C18785C4F00B91692 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5329C82518785C4F00B91692 /* CoreGraphics.framework in Frameworks */, + 5329C82718785C4F00B91692 /* UIKit.framework in Frameworks */, + 5329C82318785C4F00B91692 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5329C81618785C4F00B91692 = { + isa = PBXGroup; + children = ( + 5386150B187DC41B00FA2AF9 /* README */, + 5329C82818785C4F00B91692 /* SpeakEasy */, + 5329C82118785C4F00B91692 /* Frameworks */, + 5329C82018785C4F00B91692 /* Products */, + ); + sourceTree = ""; + }; + 5329C82018785C4F00B91692 /* Products */ = { + isa = PBXGroup; + children = ( + 5329C81F18785C4F00B91692 /* SpeakEasy.app */, + ); + name = Products; + sourceTree = ""; + }; + 5329C82118785C4F00B91692 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5329C82218785C4F00B91692 /* Foundation.framework */, + 5329C82418785C4F00B91692 /* CoreGraphics.framework */, + 5329C82618785C4F00B91692 /* UIKit.framework */, + 5329C84118785C4F00B91692 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5329C82818785C4F00B91692 /* SpeakEasy */ = { + isa = PBXGroup; + children = ( + 5329C83118785C4F00B91692 /* UYLAppDelegate.h */, + 5329C83218785C4F00B91692 /* UYLAppDelegate.m */, + 5329C83418785C4F00B91692 /* Main.storyboard */, + 530D9CEF23C926AC0087DFA0 /* LaunchScreen.storyboard */, + 5329C83718785C4F00B91692 /* UYLViewController.h */, + 5329C83818785C4F00B91692 /* UYLViewController.m */, + 5329C83A18785C4F00B91692 /* Images.xcassets */, + 5329C82918785C4F00B91692 /* Supporting Files */, + ); + path = SpeakEasy; + sourceTree = ""; + }; + 5329C82918785C4F00B91692 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5329C82A18785C4F00B91692 /* SpeakEasy-Info.plist */, + 5329C82B18785C4F00B91692 /* InfoPlist.strings */, + 5329C82E18785C4F00B91692 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5329C81E18785C4F00B91692 /* SpeakEasy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5329C85118785C4F00B91692 /* Build configuration list for PBXNativeTarget "SpeakEasy" */; + buildPhases = ( + 5329C81B18785C4F00B91692 /* Sources */, + 5329C81C18785C4F00B91692 /* Frameworks */, + 5329C81D18785C4F00B91692 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SpeakEasy; + productName = SpeakEasy; + productReference = 5329C81F18785C4F00B91692 /* SpeakEasy.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5329C81718785C4F00B91692 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = UYL; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + }; + buildConfigurationList = 5329C81A18785C4F00B91692 /* Build configuration list for PBXProject "SpeakEasy" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5329C81618785C4F00B91692; + productRefGroup = 5329C82018785C4F00B91692 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5329C81E18785C4F00B91692 /* SpeakEasy */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5329C81D18785C4F00B91692 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5329C83B18785C4F00B91692 /* Images.xcassets in Resources */, + 530D9CF023C926AC0087DFA0 /* LaunchScreen.storyboard in Resources */, + 5329C82D18785C4F00B91692 /* InfoPlist.strings in Resources */, + 5329C83618785C4F00B91692 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5329C81B18785C4F00B91692 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5329C82F18785C4F00B91692 /* main.m in Sources */, + 5329C83318785C4F00B91692 /* UYLAppDelegate.m in Sources */, + 5329C83918785C4F00B91692 /* UYLViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5329C82B18785C4F00B91692 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 5329C82C18785C4F00B91692 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 5329C83418785C4F00B91692 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5329C83518785C4F00B91692 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5329C84F18785C4F00B91692 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5329C85018785C4F00B91692 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5329C85218785C4F00B91692 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "SpeakEasy/SpeakEasy-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 5329C85318785C4F00B91692 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + INFOPLIST_FILE = "SpeakEasy/SpeakEasy-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5329C81A18785C4F00B91692 /* Build configuration list for PBXProject "SpeakEasy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5329C84F18785C4F00B91692 /* Debug */, + 5329C85018785C4F00B91692 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5329C85118785C4F00B91692 /* Build configuration list for PBXNativeTarget "SpeakEasy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5329C85218785C4F00B91692 /* Debug */, + 5329C85318785C4F00B91692 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5329C81718785C4F00B91692 /* Project object */; +} diff --git a/SpeakEasy/SpeakEasy/Base.lproj/Main.storyboard b/SpeakEasy/SpeakEasy/Base.lproj/Main.storyboard new file mode 100644 index 0000000..bf0a3b5 --- /dev/null +++ b/SpeakEasy/SpeakEasy/Base.lproj/Main.storyboard @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpeakEasy/SpeakEasy/Images.xcassets/AppIcon.appiconset/Contents.json b/SpeakEasy/SpeakEasy/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..19882d5 --- /dev/null +++ b/SpeakEasy/SpeakEasy/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SpeakEasy/SpeakEasy/Images.xcassets/Contents.json b/SpeakEasy/SpeakEasy/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/SpeakEasy/SpeakEasy/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SpeakEasy/SpeakEasy/LaunchScreen.storyboard b/SpeakEasy/SpeakEasy/LaunchScreen.storyboard new file mode 100644 index 0000000..6cb06fe --- /dev/null +++ b/SpeakEasy/SpeakEasy/LaunchScreen.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RemindMe/Info.plist b/SpeakEasy/SpeakEasy/SpeakEasy-Info.plist similarity index 61% rename from RemindMe/Info.plist rename to SpeakEasy/SpeakEasy/SpeakEasy-Info.plist index 3289444..bc8f3ff 100644 --- a/RemindMe/Info.plist +++ b/SpeakEasy/SpeakEasy/SpeakEasy-Info.plist @@ -3,28 +3,38 @@ CFBundleDevelopmentRegion - English + en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} - CFBundleIconFile - CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL + CFBundleShortVersionString + 1.0 CFBundleSignature ???? CFBundleVersion 1.0 LSRequiresIPhoneOS - NSMainNibFile - MainWindow + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + diff --git a/SpeakEasy/SpeakEasy/UYLAppDelegate.h b/SpeakEasy/SpeakEasy/UYLAppDelegate.h new file mode 100644 index 0000000..e176e39 --- /dev/null +++ b/SpeakEasy/SpeakEasy/UYLAppDelegate.h @@ -0,0 +1,40 @@ +// +// UYLAppDelegate.h +// SpeakEasy +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/SpeakEasy/SpeakEasy/UYLAppDelegate.m b/SpeakEasy/SpeakEasy/UYLAppDelegate.m new file mode 100644 index 0000000..dedd97c --- /dev/null +++ b/SpeakEasy/SpeakEasy/UYLAppDelegate.m @@ -0,0 +1,49 @@ +// +// UYLAppDelegate.m +// SpeakEasy +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLAppDelegate.h" + +@implementation UYLAppDelegate + +// Opt-in to state restoration +- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder +{ + return YES; +} + +- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder +{ + return YES; +} + +@end diff --git a/SpeakEasy/SpeakEasy/UYLViewController.h b/SpeakEasy/SpeakEasy/UYLViewController.h new file mode 100644 index 0000000..1455d6b --- /dev/null +++ b/SpeakEasy/SpeakEasy/UYLViewController.h @@ -0,0 +1,38 @@ +// +// UYLViewController.h +// SpeakEasy +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface UYLViewController : UIViewController + +@end diff --git a/SpeakEasy/SpeakEasy/UYLViewController.m b/SpeakEasy/SpeakEasy/UYLViewController.m new file mode 100644 index 0000000..5e5f6f0 --- /dev/null +++ b/SpeakEasy/SpeakEasy/UYLViewController.m @@ -0,0 +1,341 @@ +// +// UYLViewController.m +// SpeakEasy +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// Neither the name of Keith Harrison nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "UYLViewController.h" +#import + +@interface UYLViewController () + +@property (weak, nonatomic) IBOutlet UITextField *textInput; +@property (weak, nonatomic) IBOutlet UISegmentedControl *speedControl; +@property (weak, nonatomic) IBOutlet UISegmentedControl *pitchControl; +@property (weak, nonatomic) IBOutlet UIPickerView *languagePicker; + +@property (strong, nonatomic) NSArray *languageCodes; +@property (strong, nonatomic) NSDictionary *languageDictionary; +@property (strong, nonatomic) AVSpeechSynthesizer *synthesizer; + +typedef NS_ENUM(NSInteger, UYLSpeedControlIndex) +{ + UYLSpeedControlQuarterSpeed = 0, + UYLSpeedControlHalfSpeed = 1, + UYLSpeedControlNormalSpeed = 2, + UYLSpeedControlDoubleSpeed = 3 +}; + +typedef NS_ENUM(NSInteger, UYLPitchControlIndex) +{ + UYLPitchControlDeepPitch = 0, + UYLPitchControlNormalPitch = 1, + UYLPitchControlHighPitch = 2 +}; + +@property (assign, nonatomic) UYLSpeedControlIndex selectedSpeed; +@property (assign, nonatomic) UYLPitchControlIndex selectedPitch; +@property (strong, nonatomic) NSString *selectedLanguage; + +@property (strong, nonatomic) NSString *restoredTextToSpeak; + +@end + +@implementation UYLViewController + +NSString *UYLPrefKeySelectedSpeed = @"UYLPrefKeySelectedSpeed"; +NSString *UYLPrefKeySelectedPitch = @"UYLPrefKeySelectedPitch"; +NSString *UYLPrefKeySelectedLanguage = @"UYLPrefKeySelectedLanguage"; +NSString *UYLKeySpeechText = @"UYLKeySpeechText"; + +#pragma mark - +#pragma mark === Accessors === +#pragma mark - + +// Language codes used to create custom voices. Array is sorted based +// on the display names in the language dictionary +- (NSArray *)languageCodes +{ + if (!_languageCodes) + { + _languageCodes = [self.languageDictionary keysSortedByValueUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + } + return _languageCodes; +} + +// Map between language codes and locale specific display name +- (NSDictionary *)languageDictionary +{ + if (!_languageDictionary) + { + NSArray *voices = [AVSpeechSynthesisVoice speechVoices]; + NSArray *languages = [voices valueForKey:@"language"]; + + NSLocale *currentLocale = [NSLocale autoupdatingCurrentLocale]; + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (NSString *code in languages) + { + dictionary[code] = [currentLocale displayNameForKey:NSLocaleIdentifier value:code]; + } + _languageDictionary = dictionary; + } + return _languageDictionary; +} + +- (AVSpeechSynthesizer *)synthesizer +{ + if (!_synthesizer) + { + _synthesizer = [[AVSpeechSynthesizer alloc] init]; + _synthesizer.delegate = self; + } + return _synthesizer; +} + +#pragma mark - +#pragma mark === View Controller Life Cycle === +#pragma mark - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [self restoreUserPreferences]; + self.speedControl.selectedSegmentIndex = self.selectedSpeed; + self.pitchControl.selectedSegmentIndex = self.selectedPitch; + + NSUInteger index = [self.languageCodes indexOfObject:self.selectedLanguage]; + if (index != NSNotFound) + { + [self.languagePicker selectRow:index inComponent:0 animated:NO]; + } +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + if (self.restoredTextToSpeak) + { + self.textInput.text = self.restoredTextToSpeak; + self.restoredTextToSpeak = nil; + } +} + +#pragma mark - +#pragma mark === State Restoration === +#pragma mark - + +- (void)restoreUserPreferences +{ + NSString *currentLanguageCode = [AVSpeechSynthesisVoice currentLanguageCode]; + + NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; + NSDictionary *defaults = @{ UYLPrefKeySelectedPitch:[NSNumber numberWithInteger:UYLPitchControlNormalPitch], + UYLPrefKeySelectedSpeed:[NSNumber numberWithInteger:UYLSpeedControlNormalSpeed], + UYLPrefKeySelectedLanguage:currentLanguageCode + }; + [preferences registerDefaults:defaults]; + + self.selectedPitch = [preferences integerForKey:UYLPrefKeySelectedPitch]; + self.selectedSpeed = [preferences integerForKey:UYLPrefKeySelectedSpeed]; + self.selectedLanguage = [preferences stringForKey:UYLPrefKeySelectedLanguage]; +} + +- (void)encodeRestorableStateWithCoder:(NSCoder *)coder +{ + [coder encodeObject:self.textInput.text forKey:UYLKeySpeechText]; + [super encodeRestorableStateWithCoder:coder]; +} + +- (void)decodeRestorableStateWithCoder:(NSCoder *)coder +{ + self.restoredTextToSpeak = [coder decodeObjectForKey:UYLKeySpeechText]; + [super decodeRestorableStateWithCoder:coder]; +} + +#pragma mark - +#pragma mark === Target-Action === +#pragma mark - + +- (IBAction)speedSelected:(UISegmentedControl *)sender +{ + self.selectedSpeed = sender.selectedSegmentIndex; + NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; + [preferences setInteger:self.selectedSpeed forKey:UYLPrefKeySelectedSpeed]; + [preferences synchronize]; +} + +- (IBAction)pitchSelected:(UISegmentedControl *)sender +{ + self.selectedPitch = sender.selectedSegmentIndex; + NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; + [preferences setInteger:self.selectedPitch forKey:UYLPrefKeySelectedPitch]; + [preferences synchronize]; +} + +- (IBAction)speak:(UIButton *)sender +{ + if (self.textInput.text && !self.synthesizer.isSpeaking) + { + AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:self.selectedLanguage]; + AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:self.textInput.text]; + utterance.voice = voice; + + float adjustedRate = AVSpeechUtteranceDefaultSpeechRate * [self rateModifier]; + + if (adjustedRate > AVSpeechUtteranceMaximumSpeechRate) + { + adjustedRate = AVSpeechUtteranceMaximumSpeechRate; + } + + if (adjustedRate < AVSpeechUtteranceMinimumSpeechRate) + { + adjustedRate = AVSpeechUtteranceMinimumSpeechRate; + } + + utterance.rate = adjustedRate; + + float pitchMultiplier = [self pitchModifier]; + if ((pitchMultiplier >= 0.5) && (pitchMultiplier <= 2.0)) + { + utterance.pitchMultiplier = pitchMultiplier; + } + + [self.synthesizer speakUtterance:utterance]; + } +} + +- (float)rateModifier +{ + float rate = 1.0; + switch (self.selectedSpeed) + { + case UYLSpeedControlQuarterSpeed: + rate = 0.25; + break; + case UYLSpeedControlHalfSpeed: + rate = 0.5; + break; + case UYLSpeedControlNormalSpeed: + rate = 1.0; + break; + case UYLSpeedControlDoubleSpeed: + rate = 2.0; + break; + default: + rate = 1.0; + break; + } + return rate; +} + +- (float)pitchModifier + { + float pitch = 1.0; + switch (self.selectedPitch) + { + case UYLPitchControlDeepPitch: + pitch = 0.75; + break; + case UYLPitchControlNormalPitch: + pitch = 1.0; + break; + case UYLPitchControlHighPitch: + pitch = 1.5; + break; + default: + pitch = 1.0; + break; + } + return pitch; + } + +#pragma mark - +#pragma mark === AVSpeechSynthesizerDelegate === +#pragma mark - + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance +{ + NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:self.textInput.text]; + [text addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:characterRange]; + self.textInput.attributedText = text; +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance +{ + NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString:self.textInput.attributedText]; + [text removeAttribute:NSForegroundColorAttributeName range:NSMakeRange(0, [text length])]; + self.textInput.attributedText = text; +} + +#pragma mark - +#pragma mark === UIPickerViewDelegate === +#pragma mark - + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + return 1; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + return [self.languageCodes count]; +} + +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + self.selectedLanguage = [self.languageCodes objectAtIndex:row]; + NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; + [preferences setObject:self.selectedLanguage forKey:UYLPrefKeySelectedLanguage]; + [preferences synchronize]; +} + +#pragma mark - +#pragma mark === UIPickerViewDataSource === +#pragma mark - + +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + NSString *languageCode = self.languageCodes[row]; + NSString *languageName = self.languageDictionary[languageCode]; + return languageName; +} + +#pragma mark - +#pragma mark === UITextFieldDelegate === +#pragma mark - + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + [textField resignFirstResponder]; + return YES; +} + +@end diff --git a/SpeakEasy/SpeakEasy/en.lproj/InfoPlist.strings b/SpeakEasy/SpeakEasy/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/SpeakEasy/SpeakEasy/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/SpeakEasy/SpeakEasy/main.m b/SpeakEasy/SpeakEasy/main.m new file mode 100644 index 0000000..0222f68 --- /dev/null +++ b/SpeakEasy/SpeakEasy/main.m @@ -0,0 +1,18 @@ +// +// main.m +// SpeakEasy +// +// Created by Keith Harrison on 04/01/2014. +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// + +#import + +#import "UYLAppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([UYLAppDelegate class])); + } +} diff --git a/StackMargin/README.md b/StackMargin/README.md new file mode 100644 index 0000000..a4b28b9 --- /dev/null +++ b/StackMargin/README.md @@ -0,0 +1,7 @@ +# Adding Padding To A StackView + +How to use layout margins and the readable content guide to add padding to a stack view. The sample project shows how to do this with Interface Builder and when working with programmatic layouts. + +For further details see the blog post: + ++ [Adding padding to a stack view](https://useyourloaf.com/blog/adding-padding-to-a-stack-view/) diff --git a/StackMargin/StackMargin.xcodeproj/project.pbxproj b/StackMargin/StackMargin.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ad65d2c --- /dev/null +++ b/StackMargin/StackMargin.xcodeproj/project.pbxproj @@ -0,0 +1,348 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5315FB2D2145A86800E81704 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5315FB2C2145A86800E81704 /* AppDelegate.swift */; }; + 5315FB322145A86800E81704 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5315FB302145A86800E81704 /* Main.storyboard */; }; + 5315FB342145A86A00E81704 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5315FB332145A86A00E81704 /* Assets.xcassets */; }; + 5315FB372145A86A00E81704 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5315FB352145A86A00E81704 /* LaunchScreen.storyboard */; }; + 5315FB5A2146B0D300E81704 /* IBViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5315FB592146B0D300E81704 /* IBViewController.swift */; }; + 5315FB5C2146B12700E81704 /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5315FB5B2146B12700E81704 /* CodeViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5315FB292145A86800E81704 /* StackMargin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StackMargin.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5315FB2C2145A86800E81704 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5315FB312145A86800E81704 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5315FB332145A86A00E81704 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5315FB362145A86A00E81704 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5315FB382145A86A00E81704 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5315FB592146B0D300E81704 /* IBViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IBViewController.swift; sourceTree = ""; }; + 5315FB5B2146B12700E81704 /* CodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = ""; }; + 5315FB5D2146CCC700E81704 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5315FB262145A86800E81704 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5315FB202145A86800E81704 = { + isa = PBXGroup; + children = ( + 5315FB5D2146CCC700E81704 /* README.md */, + 5315FB2B2145A86800E81704 /* StackMargin */, + 5315FB2A2145A86800E81704 /* Products */, + ); + sourceTree = ""; + }; + 5315FB2A2145A86800E81704 /* Products */ = { + isa = PBXGroup; + children = ( + 5315FB292145A86800E81704 /* StackMargin.app */, + ); + name = Products; + sourceTree = ""; + }; + 5315FB2B2145A86800E81704 /* StackMargin */ = { + isa = PBXGroup; + children = ( + 5315FB2C2145A86800E81704 /* AppDelegate.swift */, + 5315FB592146B0D300E81704 /* IBViewController.swift */, + 5315FB5B2146B12700E81704 /* CodeViewController.swift */, + 5315FB302145A86800E81704 /* Main.storyboard */, + 5315FB332145A86A00E81704 /* Assets.xcassets */, + 5315FB352145A86A00E81704 /* LaunchScreen.storyboard */, + 5315FB382145A86A00E81704 /* Info.plist */, + ); + path = StackMargin; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5315FB282145A86800E81704 /* StackMargin */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5315FB3B2145A86A00E81704 /* Build configuration list for PBXNativeTarget "StackMargin" */; + buildPhases = ( + 5315FB252145A86800E81704 /* Sources */, + 5315FB262145A86800E81704 /* Frameworks */, + 5315FB272145A86800E81704 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = StackMargin; + productName = StackMargin; + productReference = 5315FB292145A86800E81704 /* StackMargin.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5315FB212145A86800E81704 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5315FB282145A86800E81704 = { + CreatedOnToolsVersion = 10.0; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 5315FB242145A86800E81704 /* Build configuration list for PBXProject "StackMargin" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5315FB202145A86800E81704; + productRefGroup = 5315FB2A2145A86800E81704 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5315FB282145A86800E81704 /* StackMargin */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5315FB272145A86800E81704 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5315FB372145A86A00E81704 /* LaunchScreen.storyboard in Resources */, + 5315FB342145A86A00E81704 /* Assets.xcassets in Resources */, + 5315FB322145A86800E81704 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5315FB252145A86800E81704 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5315FB5C2146B12700E81704 /* CodeViewController.swift in Sources */, + 5315FB2D2145A86800E81704 /* AppDelegate.swift in Sources */, + 5315FB5A2146B0D300E81704 /* IBViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5315FB302145A86800E81704 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5315FB312145A86800E81704 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5315FB352145A86A00E81704 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5315FB362145A86A00E81704 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5315FB392145A86A00E81704 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5315FB3A2145A86A00E81704 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5315FB3C2145A86A00E81704 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = StackMargin/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.StackMargin; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5315FB3D2145A86A00E81704 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = StackMargin/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.StackMargin; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5315FB242145A86800E81704 /* Build configuration list for PBXProject "StackMargin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5315FB392145A86A00E81704 /* Debug */, + 5315FB3A2145A86A00E81704 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5315FB3B2145A86A00E81704 /* Build configuration list for PBXNativeTarget "StackMargin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5315FB3C2145A86A00E81704 /* Debug */, + 5315FB3D2145A86A00E81704 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5315FB212145A86800E81704 /* Project object */; +} diff --git a/StackMargin/StackMargin/AppDelegate.swift b/StackMargin/StackMargin/AppDelegate.swift new file mode 100644 index 0000000..85205c0 --- /dev/null +++ b/StackMargin/StackMargin/AppDelegate.swift @@ -0,0 +1,34 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/StackMargin/StackMargin/Assets.xcassets/AppIcon.appiconset/Contents.json b/StackMargin/StackMargin/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/StackMargin/StackMargin/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/StackMargin/StackMargin/Assets.xcassets/Contents.json b/StackMargin/StackMargin/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/StackMargin/StackMargin/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/StackMargin/StackMargin/Base.lproj/LaunchScreen.storyboard b/StackMargin/StackMargin/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/StackMargin/StackMargin/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StackMargin/StackMargin/Base.lproj/Main.storyboard b/StackMargin/StackMargin/Base.lproj/Main.storyboard new file mode 100644 index 0000000..966a3c5 --- /dev/null +++ b/StackMargin/StackMargin/Base.lproj/Main.storyboard @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StackMargin/StackMargin/CodeViewController.swift b/StackMargin/StackMargin/CodeViewController.swift new file mode 100644 index 0000000..a580386 --- /dev/null +++ b/StackMargin/StackMargin/CodeViewController.swift @@ -0,0 +1,113 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class CodeViewController: UIViewController { + private let chapterLabel: UILabel = { + let label = UILabel() + label.font = UIFont.preferredFont(forTextStyle: .headline) + label.numberOfLines = 0 + label.adjustsFontForContentSizeCategory = true + label.backgroundColor = .white + return label + }() + + private let textView: UITextView = { + let textView = UITextView() + textView.font = UIFont.preferredFont(forTextStyle: .body) + textView.adjustsFontForContentSizeCategory = true + textView.isScrollEnabled = false + textView.isEditable = false + return textView + }() + + private lazy var stackView: UIStackView = { + let stackView = UIStackView(arrangedSubviews: [chapterLabel, textView]) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.spacing = UIStackView.spacingUseSystem + return stackView + }() + + private lazy var containerView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20) + view.addSubview(stackView) + view.backgroundColor = .red + + let readable = view.readableContentGuide + NSLayoutConstraint.activate([ + stackView.leadingAnchor.constraint(equalTo: readable.leadingAnchor), + stackView.topAnchor.constraint(equalTo: readable.topAnchor), + stackView.trailingAnchor.constraint(equalTo: readable.trailingAnchor), + stackView.bottomAnchor.constraint(equalTo: readable.bottomAnchor), + ]) + return view + }() + + private lazy var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.addSubview(containerView) + return scrollView + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + + chapterLabel.text = "Down the Rabbit-Hole" + textView.text = """ + Alice was beginning to get very tired of sitting by her sister on the \ + bank, and of having nothing to do: once or twice she had peeped into the \ + book her sister was reading, but it had no pictures or conversations in \ + it, ‘and what is the use of a book,’ thought Alice ‘without pictures or \ + conversations?’ + """ + } + + private func setupView() { + view.addSubview(scrollView) + + NSLayoutConstraint.activate([ + scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + scrollView.topAnchor.constraint(equalTo: view.topAnchor), + scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + + scrollView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + scrollView.topAnchor.constraint(equalTo: containerView.topAnchor), + scrollView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + + scrollView.widthAnchor.constraint(equalTo: containerView.widthAnchor), + ]) + } +} diff --git a/StackMargin/StackMargin/IBViewController.swift b/StackMargin/StackMargin/IBViewController.swift new file mode 100644 index 0000000..b7dc7b9 --- /dev/null +++ b/StackMargin/StackMargin/IBViewController.swift @@ -0,0 +1,67 @@ +// Copyright © 2018 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class IBViewController: UIViewController { + @IBOutlet var stackView: UIStackView! + @IBOutlet var chapterLabel: UILabel! + @IBOutlet var textView: UITextView! + + override func viewDidLoad() { + super.viewDidLoad() + setupView() + + chapterLabel.text = "Down the Rabbit-Hole" + textView.text = """ + Alice was beginning to get very tired of sitting by her sister on the \ + bank, and of having nothing to do: once or twice she had peeped into the \ + book her sister was reading, but it had no pictures or conversations in \ + it, ‘and what is the use of a book,’ thought Alice ‘without pictures or \ + conversations?’ + """ + } + + private let backgroundView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .red + return view + }() + + private func setupView() { + stackView.insertSubview(backgroundView, at: 0) + + NSLayoutConstraint.activate([ + backgroundView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor), + backgroundView.topAnchor.constraint(equalTo: stackView.topAnchor), + backgroundView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor), + backgroundView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor) + ]) + } +} diff --git a/StackMargin/StackMargin/Info.plist b/StackMargin/StackMargin/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/StackMargin/StackMargin/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Stacks/README.md b/Stacks/README.md new file mode 100644 index 0000000..232736c --- /dev/null +++ b/Stacks/README.md @@ -0,0 +1,47 @@ +### Stacks + +Examples of using and sometime abusing stack views (requires iOS 9) + +#### Basic Stack View Usage + +Example of how to use UIStackView to simplify layout of horizontal and +vertical arrangements of views. See the following post for details: + ++ [Easier Auto Layout with Stack Views](https://useyourloaf.com/blog/easier-autolayout-with-stackviews/) + +#### Using Stack Views with Size Classes + +Also see this post for details on how to have the stack view automatically +adapt to size class changes: + ++ [Adapting Stack Views with Size Classes](https://useyourloaf.com/blog/adapting-stack-views-with-size-classes/) + +#### Hiding Views in a Stack View + +The third view controller - HiddenViewController is an example of how to +use size classes to hide a view contained in a stack view. See this post +for details: + ++ [Using Size Classes to Hide Stack View Contents](https://useyourloaf.com/blog/using-size-classes-to-hide-stack-view-contents/) + +#### 3D Touch Quick Actions + +Quick actions allow the user to launch the app directly to one of the three tabs. +See this post for details: + ++ [Adding 3D Touch Quick Actions](https://useyourloaf.com/blog/adding-3d-touch-quick-actions/) + +#### Scrolling Stack View + +The ScrollingStackViewController provides an example of how to embed a +stack view in a scroll view. See this post for details: + ++ [Scroll Stack Views](https://useyourloaf.com/blog/scrolling-stack-views/) + +#### Version History + ++ Version 1.4 12 Mar 2016 Add a scrolling stack view ++ Version 1.3 05 Oct 2015 Add static quick actions ++ Version 1.2 27 Sep 2015 Hide a view for compact height ++ Version 1.1 06 July 2015 Adapting axis to view size classes ++ Version 1.0 22 June 2015 Initial version. diff --git a/Stacks/Stacks.xcodeproj/project.pbxproj b/Stacks/Stacks.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9605874 --- /dev/null +++ b/Stacks/Stacks.xcodeproj/project.pbxproj @@ -0,0 +1,352 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5378799F1B49BA6A004CBDC1 /* SizeClassViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5378799E1B49BA6A004CBDC1 /* SizeClassViewController.swift */; }; + 5395B1371BB48B4700CF54F7 /* HiddenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5395B1361BB48B4700CF54F7 /* HiddenViewController.swift */; }; + 53B55B951BC1B89A0071291E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53B55B981BC1B89A0071291E /* InfoPlist.strings */; }; + 53DA13EE1B32184600FEEE79 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53DA13ED1B32184600FEEE79 /* AppDelegate.swift */; }; + 53DA13F01B32184600FEEE79 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53DA13EF1B32184600FEEE79 /* ViewController.swift */; }; + 53DA13F31B32184600FEEE79 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53DA13F11B32184600FEEE79 /* Main.storyboard */; }; + 53DA13F51B32184600FEEE79 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53DA13F41B32184600FEEE79 /* Assets.xcassets */; }; + 53DA13F81B32184600FEEE79 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53DA13F61B32184600FEEE79 /* LaunchScreen.storyboard */; }; + 53E9DC1B1C90E0FB00C9A89C /* ScrollingStackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E9DC1A1C90E0FB00C9A89C /* ScrollingStackViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5378799E1B49BA6A004CBDC1 /* SizeClassViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizeClassViewController.swift; sourceTree = ""; }; + 5395B1361BB48B4700CF54F7 /* HiddenViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HiddenViewController.swift; sourceTree = ""; }; + 53B55B971BC1B89A0071291E /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; }; + 53BB4E981C94C22D0019483F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 53DA13EA1B32184600FEEE79 /* Stacks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stacks.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53DA13ED1B32184600FEEE79 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53DA13EF1B32184600FEEE79 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 53DA13F21B32184600FEEE79 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53DA13F41B32184600FEEE79 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53DA13F71B32184600FEEE79 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53DA13F91B32184600FEEE79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53E9DC1A1C90E0FB00C9A89C /* ScrollingStackViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollingStackViewController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53DA13E71B32184600FEEE79 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53DA13E11B32184500FEEE79 = { + isa = PBXGroup; + children = ( + 53BB4E981C94C22D0019483F /* README.md */, + 53DA13EC1B32184600FEEE79 /* Stacks */, + 53DA13EB1B32184600FEEE79 /* Products */, + ); + sourceTree = ""; + }; + 53DA13EB1B32184600FEEE79 /* Products */ = { + isa = PBXGroup; + children = ( + 53DA13EA1B32184600FEEE79 /* Stacks.app */, + ); + name = Products; + sourceTree = ""; + }; + 53DA13EC1B32184600FEEE79 /* Stacks */ = { + isa = PBXGroup; + children = ( + 53DA13ED1B32184600FEEE79 /* AppDelegate.swift */, + 53DA13EF1B32184600FEEE79 /* ViewController.swift */, + 53DA13F11B32184600FEEE79 /* Main.storyboard */, + 53E9DC1A1C90E0FB00C9A89C /* ScrollingStackViewController.swift */, + 5378799E1B49BA6A004CBDC1 /* SizeClassViewController.swift */, + 5395B1361BB48B4700CF54F7 /* HiddenViewController.swift */, + 53DA13F41B32184600FEEE79 /* Assets.xcassets */, + 53DA13F61B32184600FEEE79 /* LaunchScreen.storyboard */, + 53DA13F91B32184600FEEE79 /* Info.plist */, + 53B55B981BC1B89A0071291E /* InfoPlist.strings */, + ); + path = Stacks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53DA13E91B32184600FEEE79 /* Stacks */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53DA14121B32184600FEEE79 /* Build configuration list for PBXNativeTarget "Stacks" */; + buildPhases = ( + 53DA13E61B32184600FEEE79 /* Sources */, + 53DA13E71B32184600FEEE79 /* Frameworks */, + 53DA13E81B32184600FEEE79 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Stacks; + productName = Stacks; + productReference = 53DA13EA1B32184600FEEE79 /* Stacks.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53DA13E21B32184500FEEE79 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53DA13E91B32184600FEEE79 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 53DA13E51B32184500FEEE79 /* Build configuration list for PBXProject "Stacks" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53DA13E11B32184500FEEE79; + productRefGroup = 53DA13EB1B32184600FEEE79 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53DA13E91B32184600FEEE79 /* Stacks */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53DA13E81B32184600FEEE79 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53DA13F81B32184600FEEE79 /* LaunchScreen.storyboard in Resources */, + 53B55B951BC1B89A0071291E /* InfoPlist.strings in Resources */, + 53DA13F51B32184600FEEE79 /* Assets.xcassets in Resources */, + 53DA13F31B32184600FEEE79 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53DA13E61B32184600FEEE79 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53E9DC1B1C90E0FB00C9A89C /* ScrollingStackViewController.swift in Sources */, + 5395B1371BB48B4700CF54F7 /* HiddenViewController.swift in Sources */, + 53DA13F01B32184600FEEE79 /* ViewController.swift in Sources */, + 53DA13EE1B32184600FEEE79 /* AppDelegate.swift in Sources */, + 5378799F1B49BA6A004CBDC1 /* SizeClassViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53B55B981BC1B89A0071291E /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 53B55B971BC1B89A0071291E /* Base */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 53DA13F11B32184600FEEE79 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53DA13F21B32184600FEEE79 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53DA13F61B32184600FEEE79 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53DA13F71B32184600FEEE79 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53DA14101B32184600FEEE79 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53DA14111B32184600FEEE79 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53DA14131B32184600FEEE79 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = Stacks/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Stacks; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53DA14141B32184600FEEE79 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = Stacks/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Stacks; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53DA13E51B32184500FEEE79 /* Build configuration list for PBXProject "Stacks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53DA14101B32184600FEEE79 /* Debug */, + 53DA14111B32184600FEEE79 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53DA14121B32184600FEEE79 /* Build configuration list for PBXNativeTarget "Stacks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53DA14131B32184600FEEE79 /* Debug */, + 53DA14141B32184600FEEE79 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53DA13E21B32184500FEEE79 /* Project object */; +} diff --git a/Stacks/Stacks/AppDelegate.swift b/Stacks/Stacks/AppDelegate.swift new file mode 100644 index 0000000..d0300c9 --- /dev/null +++ b/Stacks/Stacks/AppDelegate.swift @@ -0,0 +1,100 @@ +// +// AppDelegate.swift +// Stacks +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + enum ShortcutIdentifier: String { + case OpenFavorites + case OpenFeatured + case OpenTopRated + + init?(fullIdentifier: String) { + guard let shortIdentifier = fullIdentifier.components(separatedBy: ".").last else { + return nil + } + self.init(rawValue: shortIdentifier) + } + } + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem { + + handleShortcut(shortcutItem) + return false + } + + return true + } + + func application(_ application: UIApplication, + performActionFor shortcutItem: UIApplicationShortcutItem, + completionHandler: @escaping (Bool) -> Void) { + + completionHandler(handleShortcut(shortcutItem)) + } + + @discardableResult private func handleShortcut(_ shortcutItem: UIApplicationShortcutItem) -> Bool { + + let shortcutType = shortcutItem.type + guard let shortcutIdentifier = ShortcutIdentifier(fullIdentifier: shortcutType) else { + return false + } + + return selectTabBarItemForIdentifier(shortcutIdentifier) + } + + private func selectTabBarItemForIdentifier(_ identifier: ShortcutIdentifier) -> Bool { + + guard let tabBarController = self.window?.rootViewController as? UITabBarController else { + return false + } + + switch (identifier) { + case .OpenFavorites: + tabBarController.selectedIndex = 0 + return true + case .OpenFeatured: + tabBarController.selectedIndex = 1 + return true + case .OpenTopRated: + tabBarController.selectedIndex = 2 + return true + } + } +} diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/Contents.json b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1018f64 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-42.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-120.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-121.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-180.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-41.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-167.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000..4a1a9de Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-120.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-120.png new file mode 100644 index 0000000..fac9448 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-120.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-121.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-121.png new file mode 100644 index 0000000..fac9448 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-121.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-167.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-167.png new file mode 100644 index 0000000..0a5ec66 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-167.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-180.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-180.png new file mode 100644 index 0000000..fd2fbe9 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-180.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-20.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-20.png new file mode 100644 index 0000000..3c16adf Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-20.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000..b257b07 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x-1.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x-1.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x-1.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000..7759c83 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png new file mode 100644 index 0000000..7a8cd5d Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000..95e7063 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x-1.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x-1.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x-1.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000..611f339 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-41.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-41.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-41.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-42.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-42.png new file mode 100644 index 0000000..c663546 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-42.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-60.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-60.png new file mode 100644 index 0000000..fd2eff6 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-60.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000..89ca713 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000..7bdbed3 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Contents.json b/Stacks/Stacks/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/Heart.imageset/Contents.json b/Stacks/Stacks/Assets.xcassets/Heart.imageset/Contents.json new file mode 100644 index 0000000..fe5ada5 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/Heart.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "heart120.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "heart240.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "heart360.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart120.png b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart120.png new file mode 100644 index 0000000..3dd922e Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart120.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart240.png b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart240.png new file mode 100644 index 0000000..1ecead5 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart240.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart360.png b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart360.png new file mode 100644 index 0000000..b127587 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Heart.imageset/heart360.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/Contents.json b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Contents.json b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Contents.json new file mode 100644 index 0000000..7c0a4bb --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Eye35.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Eye70.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Eye105.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye105.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye105.png new file mode 100644 index 0000000..52d59ef Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye105.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye35.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye35.png new file mode 100644 index 0000000..fae96ef Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye35.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye70.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye70.png new file mode 100644 index 0000000..6d8cc99 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/EyeTemplate.imageset/Eye70.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Contents.json b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Contents.json new file mode 100644 index 0000000..e78fc26 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Heart35.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Heart70.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Heart105.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart105.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart105.png new file mode 100644 index 0000000..66653a6 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart105.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart35.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart35.png new file mode 100644 index 0000000..beb28d8 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart35.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart70.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart70.png new file mode 100644 index 0000000..517b87f Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/HeartTemplate.imageset/Heart70.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Contents.json b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Contents.json new file mode 100644 index 0000000..ca5da25 --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Star35.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Star70.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Star105.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star105.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star105.png new file mode 100644 index 0000000..54fe294 Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star105.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star35.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star35.png new file mode 100644 index 0000000..32cacaf Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star35.png differ diff --git a/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star70.png b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star70.png new file mode 100644 index 0000000..2bd119b Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/ShortcutIcons/StarTemplate.imageset/Star70.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Star.imageset/Contents.json b/Stacks/Stacks/Assets.xcassets/Star.imageset/Contents.json new file mode 100644 index 0000000..6c96d4c --- /dev/null +++ b/Stacks/Stacks/Assets.xcassets/Star.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star120.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "star240.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "star360.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Stacks/Stacks/Assets.xcassets/Star.imageset/star120.png b/Stacks/Stacks/Assets.xcassets/Star.imageset/star120.png new file mode 100644 index 0000000..dd1860f Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Star.imageset/star120.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Star.imageset/star240.png b/Stacks/Stacks/Assets.xcassets/Star.imageset/star240.png new file mode 100644 index 0000000..3e956cc Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Star.imageset/star240.png differ diff --git a/Stacks/Stacks/Assets.xcassets/Star.imageset/star360.png b/Stacks/Stacks/Assets.xcassets/Star.imageset/star360.png new file mode 100644 index 0000000..dc8514c Binary files /dev/null and b/Stacks/Stacks/Assets.xcassets/Star.imageset/star360.png differ diff --git a/Stacks/Stacks/Base.lproj/InfoPlist.strings b/Stacks/Stacks/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000..5c672cd --- /dev/null +++ b/Stacks/Stacks/Base.lproj/InfoPlist.strings @@ -0,0 +1,15 @@ +/* + InfoPlist.strings + Stacks + + Created by Keith Harrison on 04/10/2015. + Copyright © 2015 Keith Harrison. All rights reserved. +*/ +shortcutTitleFavorites = "Favorites"; +shortcutSubtitleFavorites = "What you like"; + +shortcutTitleFeatured = "Featured"; +shortcutSubtitleFeatured = "What we like"; + +shortcutTitleTopRated = "Top Rated"; +shortcutSubtitleTopRated = "What others like"; diff --git a/Stacks/Stacks/Base.lproj/LaunchScreen.storyboard b/Stacks/Stacks/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..9811301 --- /dev/null +++ b/Stacks/Stacks/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stacks/Stacks/Base.lproj/Main.storyboard b/Stacks/Stacks/Base.lproj/Main.storyboard new file mode 100644 index 0000000..efc7d33 --- /dev/null +++ b/Stacks/Stacks/Base.lproj/Main.storyboard @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Stacks/Stacks/HiddenViewController.swift b/Stacks/Stacks/HiddenViewController.swift new file mode 100644 index 0000000..6943606 --- /dev/null +++ b/Stacks/Stacks/HiddenViewController.swift @@ -0,0 +1,55 @@ +// +// HiddenViewController.swift +// Stacks +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class HiddenViewController: UIViewController { + @IBOutlet private var extraHeart: UIImageView! + + override func viewDidLoad() { + super.viewDidLoad() + configureView(traitCollection.verticalSizeClass) + } + + override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { + super.willTransition(to: newCollection, with: coordinator) + configureView(newCollection.verticalSizeClass) + } + + private func configureView(_ verticalSizeClass: UIUserInterfaceSizeClass) { + guard extraHeart != nil else { + return + } + extraHeart.isHidden = (verticalSizeClass == .compact) + } +} diff --git a/Stacks/Stacks/Info.plist b/Stacks/Stacks/Info.plist new file mode 100644 index 0000000..1f7589c --- /dev/null +++ b/Stacks/Stacks/Info.plist @@ -0,0 +1,96 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.4 + CFBundleSignature + ???? + CFBundleVersion + 4 + LSRequiresIPhoneOS + + UIApplicationShortcutItems + + + UIApplicationShortcutItemIconFile + StarTemplate + UIApplicationShortcutItemSubtitle + shortcutSubtitleFavorites + UIApplicationShortcutItemTitle + shortcutTitleFavorites + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).OpenFavorites + UIApplicationShortcutItemUserInfo + + version + 3 + + + + UIApplicationShortcutItemIconFile + EyeTemplate + UIApplicationShortcutItemSubtitle + shortcutSubtitleFeatured + UIApplicationShortcutItemTitle + shortcutTitleFeatured + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).OpenFeatured + UIApplicationShortcutItemUserInfo + + version + 3 + + + + UIApplicationShortcutItemIconFile + HeartTemplate + UIApplicationShortcutItemSubtitle + shortcutSubtitleTopRated + UIApplicationShortcutItemTitle + shortcutTitleTopRated + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).OpenTopRated + UIApplicationShortcutItemUserInfo + + version + 3 + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Stacks/Stacks/ScrollingStackViewController.swift b/Stacks/Stacks/ScrollingStackViewController.swift new file mode 100644 index 0000000..2363417 --- /dev/null +++ b/Stacks/Stacks/ScrollingStackViewController.swift @@ -0,0 +1,69 @@ +// +// ScrollingStackViewController.swift +// Stacks +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ScrollingStackViewController: UIViewController { + @IBOutlet private var scrollView: UIScrollView! + @IBOutlet private var stackView: UIStackView! + + @IBAction func singleTap(_ sender: UITapGestureRecognizer) { + let heartImage = UIImage(named: "Heart") + let heartImageView = UIImageView(image: heartImage) + stackView.addArrangedSubview(heartImageView) + scrollToEnd(heartImageView) + } + + @IBAction func twoFingerTap(_ sender: UITapGestureRecognizer) { + let starImage = UIImage(named: "Star") + let starImageView = UIImageView(image: starImage) + stackView.addArrangedSubview(starImageView) + scrollToEnd(starImageView) + } + + @IBAction func threeFingerTap(_ sender: UITapGestureRecognizer) { + let views = stackView.arrangedSubviews + for entry in views { + stackView.removeArrangedSubview(entry) + entry.removeFromSuperview() + } + } + + private func scrollToEnd(_ addedView: UIView) { + let contentViewHeight = scrollView.contentSize.height + addedView.bounds.height + stackView.spacing + let offsetY = contentViewHeight - scrollView.bounds.height + if offsetY > 0 { + scrollView.setContentOffset(CGPoint(x: scrollView.contentOffset.x, y: offsetY), animated: true) + } + } +} diff --git a/Stacks/Stacks/SizeClassViewController.swift b/Stacks/Stacks/SizeClassViewController.swift new file mode 100644 index 0000000..de4e79b --- /dev/null +++ b/Stacks/Stacks/SizeClassViewController.swift @@ -0,0 +1,66 @@ +// +// SizeClassViewController.swift +// Stacks +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class SizeClassViewController: UIViewController { + @IBOutlet private var stackView: UIStackView! + + // The alignment axis of the stack view should be set correctly in the Storyboard + // for the given size classes. It should be horizontal except for when the view + // has a compact width and a regular height. This did not work in early iOS 9 + // beta releases. It was fixed in iOS 9 beta 4. + + // The following code was a workaround to the bug that was fixed in iOS 9 beta 4. + // Uncomment if you want to change the stack view axis when the view changes + // size (you can then remove the size class constraints from the stack view in + // the Storyboard). + +// override func viewDidLoad() { +// super.viewDidLoad() +// configureViewForSize(view.bounds.size) +// } +// +// override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { +// super.viewWillTransition(to: size, with: coordinator) +// configureViewForSize(size) +// } +// +// private func configureViewForSize(_ size: CGSize) { +// if size.width > size.height { +// stackView.axis = .horizontal +// } else { +// stackView.axis = .vertical +// } +// } +} diff --git a/Stacks/Stacks/ViewController.swift b/Stacks/Stacks/ViewController.swift new file mode 100644 index 0000000..f172d89 --- /dev/null +++ b/Stacks/Stacks/ViewController.swift @@ -0,0 +1,58 @@ +// +// ViewController.swift +// Stacks +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ViewController: UIViewController { + @IBOutlet private var axisSwitch: UISwitch! + @IBOutlet private var stackView: UIStackView! + + @IBAction func axisChange(_ sender: UISwitch) { + UIView.animate(withDuration: 1.0, animations: { + self.updateConstraintsForAxis() + }) + } + + override func viewDidLoad() { + super.viewDidLoad() + updateConstraintsForAxis() + } + + private func updateConstraintsForAxis() { + if axisSwitch.isOn { + stackView.axis = .horizontal + } else { + stackView.axis = .vertical + } + } +} diff --git a/StaticTable/StaticTable/UYLFirstViewController.xib b/StaticTable/StaticTable/UYLFirstViewController.xib deleted file mode 100644 index 5df5285..0000000 --- a/StaticTable/StaticTable/UYLFirstViewController.xib +++ /dev/null @@ -1,223 +0,0 @@ - - - - 1296 - 11D50 - 2182 - 1138.32 - 568.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUIView - IBUILabel - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 298 - {{20, 155}, {280, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - First View Controller - - 1 - MCAwIDAAA - - - 0 - 10 - 1 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - {{0, 64}, {320, 367}} - - - - - 10 - - 549453824 - {512, 1} - - - - - - TU0AKgAACAjFzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/ -y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/ -xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/ -xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/ -xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/ -xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/ -xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/ -y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/ -y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/ -xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/ -xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/ -xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/ -xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/ -xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/ -y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/ -y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/ -xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/ -xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/ -xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/ -xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/ -xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/ -y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/ -y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/ -xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/ -xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/ -xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/ -xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/ -xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/ -y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/ -y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/ -xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/ -xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/ -xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/xczS/8vS2P/L0tj/xczU/8XM1P/FzNT/ -xczU/8XM0v/L0tj/y9LY/8XM1P/FzNT/xczU/8XM1P/FzNL/y9LY/8vS2P/FzNT/xczU/8XM1P/FzNT/ -xczS/8vS2P/L0tj/xczU/wANAQAAAwAAAAECAAAAAQEAAwAAAAEAAQAAAQIAAwAAAAQAAAiqAQMAAwAA -AAEAAQAAAQYAAwAAAAEAAgAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEABAAAARYAAwAA -AAEAAQAAARcABAAAAAEAAAgAARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAQAAAiyAAAAAAAI -AAgACAAIAAEAAQABAAE - - - - - - 3 - MCAwAA - - - groupTableViewBackgroundColor - - - - NO - - - IBCocoaTouchFramework - - - - - - - view - - - - 3 - - - - - - 0 - - - - - - 1 - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 5 - - - - - - - UYLFirstViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 5 - - - - - UYLFirstViewController - UIViewController - - IBProjectSource - ./Classes/UYLFirstViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - diff --git a/StaticTableDynamicType/README.md b/StaticTableDynamicType/README.md new file mode 100644 index 0000000..6c03a7e --- /dev/null +++ b/StaticTableDynamicType/README.md @@ -0,0 +1,11 @@ +### Static Table View Support for Dynamic Type + +*The workarounds in this project should only be required if you need to deploy back to iOS 9 or earlier.* + +A look at how to get dynamic type working with static table views. See the following post further details: + ++ [Static Tables and Dynamic Type](https://useyourloaf.com/blog/static-tables-and-dynamic-type/) + +#### Version History + ++ Version 1.0 25 Apr 2016 Initial Version \ No newline at end of file diff --git a/StaticTableDynamicType/StaticTable.xcodeproj/project.pbxproj b/StaticTableDynamicType/StaticTable.xcodeproj/project.pbxproj new file mode 100644 index 0000000..24d8da8 --- /dev/null +++ b/StaticTableDynamicType/StaticTable.xcodeproj/project.pbxproj @@ -0,0 +1,348 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 5347A3BA1CC968FF00154F49 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5347A3B91CC968FF00154F49 /* AppDelegate.swift */; }; + 5347A3BF1CC968FF00154F49 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5347A3BD1CC968FF00154F49 /* Main.storyboard */; }; + 5347A3C11CC968FF00154F49 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5347A3C01CC968FF00154F49 /* Assets.xcassets */; }; + 5347A3C41CC968FF00154F49 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5347A3C21CC968FF00154F49 /* LaunchScreen.storyboard */; }; + 5347A3CC1CC9699D00154F49 /* StaticTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5347A3CB1CC9699D00154F49 /* StaticTableViewController.swift */; }; + 5347A3CE1CC96DBE00154F49 /* UYLBasicStaticTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5347A3CD1CC96DBE00154F49 /* UYLBasicStaticTableViewCell.swift */; }; + 53CF6F8D1CCA79D200152B9B /* UYLPreferredFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53CF6F8C1CCA79D200152B9B /* UYLPreferredFont.swift */; }; + 53CF6F8F1CCA7BDF00152B9B /* UYLSubtitleStaticTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53CF6F8E1CCA7BDF00152B9B /* UYLSubtitleStaticTableViewCell.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5347A3B61CC968FF00154F49 /* StaticTable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StaticTable.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5347A3B91CC968FF00154F49 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 5347A3BE1CC968FF00154F49 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5347A3C01CC968FF00154F49 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5347A3C31CC968FF00154F49 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5347A3C51CC968FF00154F49 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5347A3CB1CC9699D00154F49 /* StaticTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticTableViewController.swift; sourceTree = ""; }; + 5347A3CD1CC96DBE00154F49 /* UYLBasicStaticTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UYLBasicStaticTableViewCell.swift; sourceTree = ""; }; + 53CF6F8C1CCA79D200152B9B /* UYLPreferredFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UYLPreferredFont.swift; sourceTree = ""; }; + 53CF6F8E1CCA7BDF00152B9B /* UYLSubtitleStaticTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UYLSubtitleStaticTableViewCell.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5347A3B31CC968FF00154F49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5347A3AD1CC968FF00154F49 = { + isa = PBXGroup; + children = ( + 5347A3B81CC968FF00154F49 /* StaticTable */, + 5347A3B71CC968FF00154F49 /* Products */, + ); + sourceTree = ""; + }; + 5347A3B71CC968FF00154F49 /* Products */ = { + isa = PBXGroup; + children = ( + 5347A3B61CC968FF00154F49 /* StaticTable.app */, + ); + name = Products; + sourceTree = ""; + }; + 5347A3B81CC968FF00154F49 /* StaticTable */ = { + isa = PBXGroup; + children = ( + 5347A3B91CC968FF00154F49 /* AppDelegate.swift */, + 5347A3CB1CC9699D00154F49 /* StaticTableViewController.swift */, + 53CF6F8C1CCA79D200152B9B /* UYLPreferredFont.swift */, + 5347A3CD1CC96DBE00154F49 /* UYLBasicStaticTableViewCell.swift */, + 53CF6F8E1CCA7BDF00152B9B /* UYLSubtitleStaticTableViewCell.swift */, + 5347A3BD1CC968FF00154F49 /* Main.storyboard */, + 5347A3C01CC968FF00154F49 /* Assets.xcassets */, + 5347A3C21CC968FF00154F49 /* LaunchScreen.storyboard */, + 5347A3C51CC968FF00154F49 /* Info.plist */, + ); + path = StaticTable; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5347A3B51CC968FF00154F49 /* StaticTable */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5347A3C81CC968FF00154F49 /* Build configuration list for PBXNativeTarget "StaticTable" */; + buildPhases = ( + 5347A3B21CC968FF00154F49 /* Sources */, + 5347A3B31CC968FF00154F49 /* Frameworks */, + 5347A3B41CC968FF00154F49 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = StaticTable; + productName = StaticTable; + productReference = 5347A3B61CC968FF00154F49 /* StaticTable.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5347A3AE1CC968FF00154F49 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0730; + LastUpgradeCheck = 1030; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5347A3B51CC968FF00154F49 = { + CreatedOnToolsVersion = 7.3; + DevelopmentTeam = LCC2J94N44; + LastSwiftMigration = 0830; + }; + }; + }; + buildConfigurationList = 5347A3B11CC968FF00154F49 /* Build configuration list for PBXProject "StaticTable" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5347A3AD1CC968FF00154F49; + productRefGroup = 5347A3B71CC968FF00154F49 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5347A3B51CC968FF00154F49 /* StaticTable */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5347A3B41CC968FF00154F49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5347A3C41CC968FF00154F49 /* LaunchScreen.storyboard in Resources */, + 5347A3C11CC968FF00154F49 /* Assets.xcassets in Resources */, + 5347A3BF1CC968FF00154F49 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5347A3B21CC968FF00154F49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5347A3CE1CC96DBE00154F49 /* UYLBasicStaticTableViewCell.swift in Sources */, + 53CF6F8F1CCA7BDF00152B9B /* UYLSubtitleStaticTableViewCell.swift in Sources */, + 53CF6F8D1CCA79D200152B9B /* UYLPreferredFont.swift in Sources */, + 5347A3BA1CC968FF00154F49 /* AppDelegate.swift in Sources */, + 5347A3CC1CC9699D00154F49 /* StaticTableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5347A3BD1CC968FF00154F49 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5347A3BE1CC968FF00154F49 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5347A3C21CC968FF00154F49 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5347A3C31CC968FF00154F49 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5347A3C61CC968FF00154F49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5347A3C71CC968FF00154F49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5347A3C91CC968FF00154F49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = StaticTable/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.StaticTable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5347A3CA1CC968FF00154F49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = StaticTable/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.StaticTable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5347A3B11CC968FF00154F49 /* Build configuration list for PBXProject "StaticTable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5347A3C61CC968FF00154F49 /* Debug */, + 5347A3C71CC968FF00154F49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5347A3C81CC968FF00154F49 /* Build configuration list for PBXNativeTarget "StaticTable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5347A3C91CC968FF00154F49 /* Debug */, + 5347A3CA1CC968FF00154F49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5347A3AE1CC968FF00154F49 /* Project object */; +} diff --git a/StaticTableDynamicType/StaticTable/AppDelegate.swift b/StaticTableDynamicType/StaticTable/AppDelegate.swift new file mode 100644 index 0000000..476d686 --- /dev/null +++ b/StaticTableDynamicType/StaticTable/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// StaticTable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} \ No newline at end of file diff --git a/StaticTableDynamicType/StaticTable/Assets.xcassets/AppIcon.appiconset/Contents.json b/StaticTableDynamicType/StaticTable/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..eeea76c --- /dev/null +++ b/StaticTableDynamicType/StaticTable/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,73 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/StaticTableDynamicType/StaticTable/Base.lproj/LaunchScreen.storyboard b/StaticTableDynamicType/StaticTable/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..06d41ed --- /dev/null +++ b/StaticTableDynamicType/StaticTable/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StaticTableDynamicType/StaticTable/Base.lproj/Main.storyboard b/StaticTableDynamicType/StaticTable/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2e49df3 --- /dev/null +++ b/StaticTableDynamicType/StaticTable/Base.lproj/Main.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StaticTableDynamicType/StaticTable/Info.plist b/StaticTableDynamicType/StaticTable/Info.plist new file mode 100644 index 0000000..40c6215 --- /dev/null +++ b/StaticTableDynamicType/StaticTable/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/StaticTableDynamicType/StaticTable/StaticTableViewController.swift b/StaticTableDynamicType/StaticTable/StaticTableViewController.swift new file mode 100644 index 0000000..1ca1f51 --- /dev/null +++ b/StaticTableDynamicType/StaticTable/StaticTableViewController.swift @@ -0,0 +1,53 @@ +// +// StaticTableViewController.swift +// StaticTable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class StaticTableViewController: UITableViewController { + // This is only necessary for iOS 9. If your minimum deployment + // target is iOS 10 select the "Automatically Adjusts Font" option + // in Interface Builder for each of the text labels. + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + if let cell = cell as? UYLPreferredFont { + cell.contentSizeChanged() + } + return cell + } + + // This is only necessary for iOS 9 which seems to ignore the setting + // in Interface Builder. + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return UITableView.automaticDimension + } +} diff --git a/StaticTableDynamicType/StaticTable/UYLBasicStaticTableViewCell.swift b/StaticTableDynamicType/StaticTable/UYLBasicStaticTableViewCell.swift new file mode 100644 index 0000000..c27509b --- /dev/null +++ b/StaticTableDynamicType/StaticTable/UYLBasicStaticTableViewCell.swift @@ -0,0 +1,19 @@ +// +// UYLBasicStaticTableViewCell.swift +// StaticTable +// +// Created by Keith Harrison on 21/04/2016. +// Copyright © 2016 Keith Harrison. All rights reserved. +// + +import UIKit + +final class UYLBasicStaticTableViewCell: UITableViewCell { + @IBOutlet private weak var titleText: UILabel! +} + +extension UYLBasicStaticTableViewCell: UYLPreferredFont { + func contentSizeChanged() { + titleText.font = UIFont.preferredFont(forTextStyle: .headline) + } +} diff --git a/StaticTableDynamicType/StaticTable/UYLPreferredFont.swift b/StaticTableDynamicType/StaticTable/UYLPreferredFont.swift new file mode 100644 index 0000000..0bdbd58 --- /dev/null +++ b/StaticTableDynamicType/StaticTable/UYLPreferredFont.swift @@ -0,0 +1,36 @@ +// +// UYLPreferredFont.swift +// StaticTable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +protocol UYLPreferredFont { + func contentSizeChanged() +} \ No newline at end of file diff --git a/StaticTableDynamicType/StaticTable/UYLSubtitleStaticTableViewCell.swift b/StaticTableDynamicType/StaticTable/UYLSubtitleStaticTableViewCell.swift new file mode 100644 index 0000000..8e8226b --- /dev/null +++ b/StaticTableDynamicType/StaticTable/UYLSubtitleStaticTableViewCell.swift @@ -0,0 +1,46 @@ +// +// UYLSubtitleStaticTableViewCell.swift +// StaticTable +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class UYLSubtitleStaticTableViewCell: UITableViewCell { + @IBOutlet private weak var titleText: UILabel! + @IBOutlet private weak var subtitleText: UILabel! +} + +extension UYLSubtitleStaticTableViewCell: UYLPreferredFont { + func contentSizeChanged() { + titleText.font = UIFont.preferredFont(forTextStyle: .headline) + subtitleText.font = UIFont.preferredFont(forTextStyle: .subheadline) + } +} diff --git a/Stepper/Stepper/en.lproj/UYLViewController.xib b/Stepper/Stepper/en.lproj/UYLViewController.xib deleted file mode 100644 index 61a93e4..0000000 --- a/Stepper/Stepper/en.lproj/UYLViewController.xib +++ /dev/null @@ -1,449 +0,0 @@ - - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBUISwitch - IBUIStepper - IBUIView - IBUILabel - IBProxyObject - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 292 - {{20, 20}, {280, 40}} - - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - UIStepper - - 1 - MSAxIDAAA - - - 1 - 10 - 1 - - 2 - 24 - - - Helvetica-Bold - 24 - 16 - - - - - 292 - {{130, 68}, {60, 50}} - - - - _NS:328 - - 1 - MCAwIDAAA - - NO - YES - 7 - NO - IBCocoaTouchFramework - 000 - - 1 - MSAxIDEAA - - - 1 - 10 - 1 - - 2 - 30 - - - Helvetica-Bold - 30 - 16 - - - - - 268 - {{113, 149}, {94, 27}} - - - - _NS:992 - NO - YES - IBCocoaTouchFramework - 0 - 0 - 100 - - - - 292 - {{154, 216}, {94, 27}} - - - - _NS:606 - NO - IBCocoaTouchFramework - 0 - 0 - YES - - - - 292 - {{20, 219}, {141, 21}} - - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - Autorepeat - - - 1 - 10 - 2 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 292 - {{154, 277}, {94, 27}} - - - _NS:606 - NO - IBCocoaTouchFramework - 0 - 0 - YES - - - - 292 - {{20, 280}, {141, 21}} - - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - Continuous - - - 1 - 10 - 2 - - - - - - 292 - {{154, 340}, {94, 27}} - - - _NS:606 - NO - IBCocoaTouchFramework - 0 - 0 - YES - - - - 292 - {{20, 340}, {141, 21}} - - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - Value wraps - - - 1 - 10 - 2 - - - - - {{0, 20}, {320, 460}} - - - - - 1 - MCAwLjUwMTk2MDgxNCAxAA - - NO - - IBCocoaTouchFramework - - - - - - - view - - - - 7 - - - - counter - - - - 12 - - - - stepper - - - - 22 - - - - stepperChanged: - - - 13 - - 11 - - - - autorepeatChanged: - - - 13 - - 19 - - - - continuousChanged: - - - 13 - - 20 - - - - wrapChanged: - - - 13 - - 21 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - - - - - - - - - - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 13 - - - - - 14 - - - - - 15 - - - - - 16 - - - - - 17 - - - - - 18 - - - - - - - UYLViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 22 - - - - - UYLViewController - UIViewController - - UILabel - UIStepper - - - - counter - UILabel - - - stepper - UIStepper - - - - IBProjectSource - ./Classes/UYLViewController.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - 933 - - diff --git a/Swiper/Swiper.xcodeproj/project.pbxproj b/Swiper/Swiper.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1b441bf --- /dev/null +++ b/Swiper/Swiper.xcodeproj/project.pbxproj @@ -0,0 +1,329 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 53AF5D0A1F2B662A00BBF2B8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53AF5D091F2B662A00BBF2B8 /* AppDelegate.swift */; }; + 53AF5D0C1F2B662A00BBF2B8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53AF5D0B1F2B662A00BBF2B8 /* ViewController.swift */; }; + 53AF5D0F1F2B662A00BBF2B8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AF5D0D1F2B662A00BBF2B8 /* Main.storyboard */; }; + 53AF5D111F2B662A00BBF2B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53AF5D101F2B662A00BBF2B8 /* Assets.xcassets */; }; + 53AF5D141F2B662A00BBF2B8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53AF5D121F2B662A00BBF2B8 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53AF5D061F2B662A00BBF2B8 /* Swiper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Swiper.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53AF5D091F2B662A00BBF2B8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53AF5D0B1F2B662A00BBF2B8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 53AF5D0E1F2B662A00BBF2B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53AF5D101F2B662A00BBF2B8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53AF5D131F2B662A00BBF2B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53AF5D151F2B662A00BBF2B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53AF5D031F2B662A00BBF2B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53AF5CFD1F2B662A00BBF2B8 = { + isa = PBXGroup; + children = ( + 53AF5D081F2B662A00BBF2B8 /* Swiper */, + 53AF5D071F2B662A00BBF2B8 /* Products */, + ); + sourceTree = ""; + }; + 53AF5D071F2B662A00BBF2B8 /* Products */ = { + isa = PBXGroup; + children = ( + 53AF5D061F2B662A00BBF2B8 /* Swiper.app */, + ); + name = Products; + sourceTree = ""; + }; + 53AF5D081F2B662A00BBF2B8 /* Swiper */ = { + isa = PBXGroup; + children = ( + 53AF5D091F2B662A00BBF2B8 /* AppDelegate.swift */, + 53AF5D0B1F2B662A00BBF2B8 /* ViewController.swift */, + 53AF5D0D1F2B662A00BBF2B8 /* Main.storyboard */, + 53AF5D101F2B662A00BBF2B8 /* Assets.xcassets */, + 53AF5D121F2B662A00BBF2B8 /* LaunchScreen.storyboard */, + 53AF5D151F2B662A00BBF2B8 /* Info.plist */, + ); + path = Swiper; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53AF5D051F2B662A00BBF2B8 /* Swiper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53AF5D181F2B662A00BBF2B8 /* Build configuration list for PBXNativeTarget "Swiper" */; + buildPhases = ( + 53AF5D021F2B662A00BBF2B8 /* Sources */, + 53AF5D031F2B662A00BBF2B8 /* Frameworks */, + 53AF5D041F2B662A00BBF2B8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Swiper; + productName = Swiper; + productReference = 53AF5D061F2B662A00BBF2B8 /* Swiper.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53AF5CFE1F2B662A00BBF2B8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 1120; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53AF5D051F2B662A00BBF2B8 = { + CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 53AF5D011F2B662A00BBF2B8 /* Build configuration list for PBXProject "Swiper" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53AF5CFD1F2B662A00BBF2B8; + productRefGroup = 53AF5D071F2B662A00BBF2B8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53AF5D051F2B662A00BBF2B8 /* Swiper */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53AF5D041F2B662A00BBF2B8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AF5D141F2B662A00BBF2B8 /* LaunchScreen.storyboard in Resources */, + 53AF5D111F2B662A00BBF2B8 /* Assets.xcassets in Resources */, + 53AF5D0F1F2B662A00BBF2B8 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53AF5D021F2B662A00BBF2B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53AF5D0C1F2B662A00BBF2B8 /* ViewController.swift in Sources */, + 53AF5D0A1F2B662A00BBF2B8 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53AF5D0D1F2B662A00BBF2B8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AF5D0E1F2B662A00BBF2B8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53AF5D121F2B662A00BBF2B8 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53AF5D131F2B662A00BBF2B8 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53AF5D161F2B662A00BBF2B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53AF5D171F2B662A00BBF2B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53AF5D191F2B662A00BBF2B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Swiper/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Swiper; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53AF5D1A1F2B662A00BBF2B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Swiper/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Swiper; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53AF5D011F2B662A00BBF2B8 /* Build configuration list for PBXProject "Swiper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53AF5D161F2B662A00BBF2B8 /* Debug */, + 53AF5D171F2B662A00BBF2B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53AF5D181F2B662A00BBF2B8 /* Build configuration list for PBXNativeTarget "Swiper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53AF5D191F2B662A00BBF2B8 /* Debug */, + 53AF5D1A1F2B662A00BBF2B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53AF5CFE1F2B662A00BBF2B8 /* Project object */; +} diff --git a/Swiper/Swiper/AppDelegate.swift b/Swiper/Swiper/AppDelegate.swift new file mode 100644 index 0000000..6420758 --- /dev/null +++ b/Swiper/Swiper/AppDelegate.swift @@ -0,0 +1,35 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/Swiper/Swiper/Assets.xcassets/AppIcon.appiconset/Contents.json b/Swiper/Swiper/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/Swiper/Swiper/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Swiper/Swiper/Base.lproj/LaunchScreen.storyboard b/Swiper/Swiper/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..5654142 --- /dev/null +++ b/Swiper/Swiper/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Swiper/Swiper/Base.lproj/Main.storyboard b/Swiper/Swiper/Base.lproj/Main.storyboard new file mode 100644 index 0000000..022df81 --- /dev/null +++ b/Swiper/Swiper/Base.lproj/Main.storyboard @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Swiper/Swiper/Info.plist b/Swiper/Swiper/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/Swiper/Swiper/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Swiper/Swiper/ViewController.swift b/Swiper/Swiper/ViewController.swift new file mode 100644 index 0000000..877487b --- /dev/null +++ b/Swiper/Swiper/ViewController.swift @@ -0,0 +1,106 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class ViewController: UIViewController { + @IBOutlet private var fullScreenConstraints: [NSLayoutConstraint]! + @IBOutlet private var halfScreenConstraints: [NSLayoutConstraint]! + @IBOutlet private var modeSwitch: UISwitch! + @IBOutlet private var countDisplay: UILabel! + + override var prefersStatusBarHidden: Bool { + if #available(iOS 11.0, *) { + return super.prefersStatusBarHidden + } else { + return fullScreenMode || super.prefersStatusBarHidden + } + } + + override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge { + return fullScreenMode ? [.bottom, .top] : UIRectEdge() + } + + private var count = 0 { + didSet { + countDisplay.text = NumberFormatter.localizedString(from: NSNumber(value: count), number: .decimal) + } + } + + private var fullScreenMode: Bool = false { + didSet { + updateAppearance() + } + } + + private func updateAppearance() { + view.layoutIfNeeded() + updateConstraints() + UIView.animate(withDuration: 0.25) { + self.updateDeferringSystemGestures() + self.view.layoutIfNeeded() + } + } + + private func updateDeferringSystemGestures() { + if #available(iOS 11.0, *) { + setNeedsUpdateOfScreenEdgesDeferringSystemGestures() + } else { + setNeedsStatusBarAppearanceUpdate() + } + } + + private func updateConstraints() { + if fullScreenMode { + halfScreenConstraints.forEach { $0.isActive = false } + fullScreenConstraints.forEach { $0.isActive = true } + } else { + fullScreenConstraints.forEach { $0.isActive = false } + halfScreenConstraints.forEach { $0.isActive = true } + } + } + + @IBAction func fullScreen(_ sender: UISwitch) { + fullScreenMode = sender.isOn + } + + @IBAction func swipeUp(_ sender: UISwipeGestureRecognizer) { + count += 1 + } + + @IBAction func swipeDown(_ sender: UISwipeGestureRecognizer) { + count -= 1 + } + + override func viewDidLoad() { + super.viewDidLoad() + modeSwitch.isOn = fullScreenMode + updateAppearance() + } +} diff --git a/TCNibLoad/Classes/OldViewController.xib b/TCNibLoad/Classes/OldViewController.xib deleted file mode 100644 index feaf2e1..0000000 --- a/TCNibLoad/Classes/OldViewController.xib +++ /dev/null @@ -1,173 +0,0 @@ - - - - 784 - 10B500 - 732 - 1038.2 - 437.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 62 - - - YES - - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - YES - - - - YES - - IBFilesOwner - - - IBFirstResponder - - - - 274 - {320, 460} - - - 3 - MQA - - NO - YES - NO - - NO - 1 - 0 - YES - 44 - 22 - 22 - - - - - YES - - - view - - - - 5 - - - - dataSource - - - - 6 - - - - delegate - - - - 7 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 4.IBEditorWindowLastContentRect - 4.IBPluginDependency - - - YES - OldViewController - UIResponder - {{329, 504}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - YES - - - - - YES - - - YES - - - - 7 - - - - YES - - OldViewController - UIViewController - - IBProjectSource - OldViewController.h - - - - - 0 - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - - 3 - 3.1 - - diff --git a/TCNibLoad/LabelCell.xib b/TCNibLoad/LabelCell.xib deleted file mode 100644 index 7ad96df..0000000 --- a/TCNibLoad/LabelCell.xib +++ /dev/null @@ -1,445 +0,0 @@ - - - - 1056 - 10J567 - 823 - 1038.35 - 462.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 132 - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - - - 256 - - - - 292 - {{20, 9}, {135, 21}} - - NO - YES - 7 - 101 - NO - IBCocoaTouchFramework - Label 1 - - 1 - MCAwIDAAA - - - 3 - MQA - - 1 - 10 - - - - 289 - {{163, 3}, {137, 21}} - - NO - YES - 7 - 102 - NO - IBCocoaTouchFramework - Label 2 - - Helvetica-Oblique - 12 - 16 - - - 1 - MCAwIDEAA - - - 1 - 10 - - - - 289 - {{163, 20}, {137, 16}} - - NO - YES - 7 - 103 - NO - IBCocoaTouchFramework - Label 3 - - Helvetica-Bold - 12 - 16 - - - 1 - MSAwIDAAA - - - 1 - 10 - - - {320, 44} - - - 3 - MCAwAA - - NO - YES - 4 - YES - IBCocoaTouchFramework - - - {320, 44} - - - 1 - MSAxIDEAA - - IBCocoaTouchFramework - 1 - - - LabelCell - - - - - - - labelCell - - - - 12 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 3 - - - - - - - - - - 4 - - - - - 10 - - - - - 11 - - - - - - - OldViewController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABDIwAAwgAAAA - - {{125, 502}, {320, 44}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - P4AAAL+AAABBoAAAwgAAAA - - - - - - - 12 - - - - - OldViewController - UITableViewController - - labelCell - UITableViewCell - - - labelCell - - labelCell - UITableViewCell - - - - IBProjectSource - Classes/OldViewController.h - - - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIAccessibility.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UINibLoading.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIResponder.h - - - - UILabel - UIView - - IBFrameworkSource - UIKit.framework/Headers/UILabel.h - - - - UIResponder - NSObject - - - - UISearchBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UISearchBar.h - - - - UISearchDisplayController - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UISearchDisplayController.h - - - - UITableViewCell - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITableViewCell.h - - - - UITableViewController - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITableViewController.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIPrintFormatter.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITextField.h - - - - UIView - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIView.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UINavigationController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UIPopoverController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UISplitViewController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITabBarController.h - - - - UIViewController - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - TCNibLoad.xcodeproj - 3 - 132 - - diff --git a/TCNibLoad/MainWindow.xib b/TCNibLoad/MainWindow.xib deleted file mode 100644 index d8f4852..0000000 --- a/TCNibLoad/MainWindow.xib +++ /dev/null @@ -1,614 +0,0 @@ - - - - 1056 - 10J567 - 823 - 1038.35 - 462.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 132 - - - YES - - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - YES - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - IBCocoaTouchFramework - - - - 1316 - - {320, 480} - - 1 - MSAxIDEAA - - NO - NO - - IBCocoaTouchFramework - YES - - - - - - 1 - - IBCocoaTouchFramework - NO - - - NSBundle - IBCocoaTouchFramework - - - - OldViewController - - 1 - - IBCocoaTouchFramework - NO - - - YES - - - - UINib - IBCocoaTouchFramework - - - - OldViewController - - 1 - - IBCocoaTouchFramework - NO - - - - - 266 - {{129, 330}, {163, 49}} - - 3 - MCAwAA - - NO - IBCocoaTouchFramework - - - - - - YES - - - window - - - - 9 - - - - delegate - - - - 99 - - - - tabBarController - - - - 113 - - - - - YES - - 0 - - - - - - 2 - - - YES - - - - - -1 - - - File's Owner - - - 3 - - - - - 106 - - - YES - - - - - - - - 107 - - - - - 108 - - - YES - - - - NSBundle - - - 109 - - - YES - - - - UINib - - - 110 - - - - - 111 - - - - - -2 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 106.IBEditorWindowLastContentRect - 106.IBPluginDependency - 107.IBPluginDependency - 108.CustomClassName - 108.IBPluginDependency - 109.CustomClassName - 109.IBPluginDependency - 110.IBPluginDependency - 111.IBPluginDependency - 2.IBAttributePlaceholdersKey - 2.IBEditorWindowLastContentRect - 2.IBPluginDependency - 3.CustomClassName - 3.IBPluginDependency - - - YES - UIApplication - UIResponder - {{1125, 676}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - OldViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - NewViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - YES - - - YES - - - {{229, 373}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - TCNibLoadAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - YES - - - - - YES - - - YES - - - - 124 - - - - YES - - NewViewController - OldViewController - - IBProjectSource - Classes/NewViewController.h - - - - OldViewController - UITableViewController - - labelCell - UITableViewCell - - - labelCell - - labelCell - UITableViewCell - - - - IBProjectSource - Classes/OldViewController.h - - - - TCNibLoadAppDelegate - NSObject - - YES - - YES - tabBarController - window - - - YES - UITabBarController - UIWindow - - - - YES - - YES - tabBarController - window - - - YES - - tabBarController - UITabBarController - - - window - UIWindow - - - - - IBProjectSource - Classes/TCNibLoadAppDelegate.h - - - - UIWindow - UIView - - IBUserSource - - - - - - YES - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIAccessibility.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UINibLoading.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIResponder.h - - - - UIApplication - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIApplication.h - - - - UIBarItem - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIBarItem.h - - - - UIResponder - NSObject - - - - UISearchBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UISearchBar.h - - - - UISearchDisplayController - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UISearchDisplayController.h - - - - UITabBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITabBar.h - - - - UITabBarController - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITabBarController.h - - - - UITabBarItem - UIBarItem - - IBFrameworkSource - UIKit.framework/Headers/UITabBarItem.h - - - - UITableViewCell - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITableViewCell.h - - - - UITableViewController - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITableViewController.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIPrintFormatter.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITextField.h - - - - UIView - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIView.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UINavigationController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UIPopoverController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UISplitViewController.h - - - - UIViewController - - - - UIViewController - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIViewController.h - - - - UIWindow - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIWindow.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - TCNibLoad.xcodeproj - 3 - 132 - - diff --git a/TableHeader/README.md b/TableHeader/README.md new file mode 100644 index 0000000..56fc831 --- /dev/null +++ b/TableHeader/README.md @@ -0,0 +1,14 @@ +### Container + +Example of creating a table view header with a variable height sized to fit +a text label subview. This folder contains both Swift and Objective-C projects. + +#### Further Information + +See the following blog post: + ++ [Variable Height Table View Header](https://useyourloaf.com/blog/variable-height-table-view-header/) + +#### Version History + ++ Version 1.0 17 Mar 2017 Initial release diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC.xcodeproj/project.pbxproj b/TableHeader/TableHeaderObjC/TableHeaderObjC.xcodeproj/project.pbxproj new file mode 100644 index 0000000..aed1668 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC.xcodeproj/project.pbxproj @@ -0,0 +1,382 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5362BE9C1E7C042700204B31 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BE9B1E7C042700204B31 /* main.m */; }; + 5362BE9F1E7C042700204B31 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BE9E1E7C042700204B31 /* AppDelegate.m */; }; + 5362BEA51E7C042700204B31 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5362BEA31E7C042700204B31 /* Main.storyboard */; }; + 5362BEA71E7C042700204B31 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5362BEA61E7C042700204B31 /* Assets.xcassets */; }; + 5362BEAA1E7C042700204B31 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5362BEA81E7C042700204B31 /* LaunchScreen.storyboard */; }; + 5362BEB51E7C04BC00204B31 /* ListTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BEB41E7C04BC00204B31 /* ListTableViewController.m */; }; + 5362BEB91E7C050E00204B31 /* ListDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BEB81E7C050E00204B31 /* ListDataSource.m */; }; + 5362BEBC1E7C1B3800204B31 /* DataCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BEBB1E7C1B3800204B31 /* DataCell.m */; }; + 5362BEBF1E7C239100204B31 /* TextTableHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 5362BEBE1E7C239100204B31 /* TextTableHeader.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5362BE971E7C042700204B31 /* TableHeaderObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TableHeaderObjC.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5362BE9B1E7C042700204B31 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5362BE9D1E7C042700204B31 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5362BE9E1E7C042700204B31 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5362BEA41E7C042700204B31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5362BEA61E7C042700204B31 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5362BEA91E7C042700204B31 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5362BEAB1E7C042700204B31 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5362BEB31E7C04BC00204B31 /* ListTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListTableViewController.h; sourceTree = ""; }; + 5362BEB41E7C04BC00204B31 /* ListTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ListTableViewController.m; sourceTree = ""; }; + 5362BEB71E7C050E00204B31 /* ListDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListDataSource.h; sourceTree = ""; }; + 5362BEB81E7C050E00204B31 /* ListDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ListDataSource.m; sourceTree = ""; }; + 5362BEBA1E7C1B3800204B31 /* DataCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataCell.h; sourceTree = ""; }; + 5362BEBB1E7C1B3800204B31 /* DataCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataCell.m; sourceTree = ""; }; + 5362BEBD1E7C239100204B31 /* TextTableHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTableHeader.h; sourceTree = ""; }; + 5362BEBE1E7C239100204B31 /* TextTableHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextTableHeader.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5362BE941E7C042700204B31 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5362BE8E1E7C042700204B31 = { + isa = PBXGroup; + children = ( + 5362BE991E7C042700204B31 /* TableHeaderObjC */, + 5362BE981E7C042700204B31 /* Products */, + ); + sourceTree = ""; + }; + 5362BE981E7C042700204B31 /* Products */ = { + isa = PBXGroup; + children = ( + 5362BE971E7C042700204B31 /* TableHeaderObjC.app */, + ); + name = Products; + sourceTree = ""; + }; + 5362BE991E7C042700204B31 /* TableHeaderObjC */ = { + isa = PBXGroup; + children = ( + 5362BEB61E7C04CB00204B31 /* Controllers */, + 5362BEB11E7C044A00204B31 /* Delegates */, + 5362BEB21E7C049800204B31 /* Views */, + 5362BE9A1E7C042700204B31 /* Supporting Files */, + ); + path = TableHeaderObjC; + sourceTree = ""; + }; + 5362BE9A1E7C042700204B31 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5362BEA61E7C042700204B31 /* Assets.xcassets */, + 5362BEAB1E7C042700204B31 /* Info.plist */, + 5362BE9B1E7C042700204B31 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 5362BEB11E7C044A00204B31 /* Delegates */ = { + isa = PBXGroup; + children = ( + 5362BE9D1E7C042700204B31 /* AppDelegate.h */, + 5362BE9E1E7C042700204B31 /* AppDelegate.m */, + 5362BEB71E7C050E00204B31 /* ListDataSource.h */, + 5362BEB81E7C050E00204B31 /* ListDataSource.m */, + ); + name = Delegates; + sourceTree = ""; + }; + 5362BEB21E7C049800204B31 /* Views */ = { + isa = PBXGroup; + children = ( + 5362BEA31E7C042700204B31 /* Main.storyboard */, + 5362BEA81E7C042700204B31 /* LaunchScreen.storyboard */, + 5362BEBA1E7C1B3800204B31 /* DataCell.h */, + 5362BEBB1E7C1B3800204B31 /* DataCell.m */, + 5362BEBD1E7C239100204B31 /* TextTableHeader.h */, + 5362BEBE1E7C239100204B31 /* TextTableHeader.m */, + ); + name = Views; + sourceTree = ""; + }; + 5362BEB61E7C04CB00204B31 /* Controllers */ = { + isa = PBXGroup; + children = ( + 5362BEB31E7C04BC00204B31 /* ListTableViewController.h */, + 5362BEB41E7C04BC00204B31 /* ListTableViewController.m */, + ); + name = Controllers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5362BE961E7C042700204B31 /* TableHeaderObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5362BEAE1E7C042700204B31 /* Build configuration list for PBXNativeTarget "TableHeaderObjC" */; + buildPhases = ( + 5362BE931E7C042700204B31 /* Sources */, + 5362BE941E7C042700204B31 /* Frameworks */, + 5362BE951E7C042700204B31 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TableHeaderObjC; + productName = TableHeaderObjC; + productReference = 5362BE971E7C042700204B31 /* TableHeaderObjC.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5362BE8F1E7C042700204B31 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 5362BE961E7C042700204B31 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 5362BE921E7C042700204B31 /* Build configuration list for PBXProject "TableHeaderObjC" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5362BE8E1E7C042700204B31; + productRefGroup = 5362BE981E7C042700204B31 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5362BE961E7C042700204B31 /* TableHeaderObjC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5362BE951E7C042700204B31 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5362BEAA1E7C042700204B31 /* LaunchScreen.storyboard in Resources */, + 5362BEA71E7C042700204B31 /* Assets.xcassets in Resources */, + 5362BEA51E7C042700204B31 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5362BE931E7C042700204B31 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5362BE9F1E7C042700204B31 /* AppDelegate.m in Sources */, + 5362BEBC1E7C1B3800204B31 /* DataCell.m in Sources */, + 5362BEBF1E7C239100204B31 /* TextTableHeader.m in Sources */, + 5362BE9C1E7C042700204B31 /* main.m in Sources */, + 5362BEB91E7C050E00204B31 /* ListDataSource.m in Sources */, + 5362BEB51E7C04BC00204B31 /* ListTableViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5362BEA31E7C042700204B31 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5362BEA41E7C042700204B31 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5362BEA81E7C042700204B31 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5362BEA91E7C042700204B31 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5362BEAC1E7C042700204B31 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5362BEAD1E7C042700204B31 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5362BEAF1E7C042700204B31 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = TableHeaderObjC/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TableHeaderObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 5362BEB01E7C042700204B31 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = TableHeaderObjC/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TableHeaderObjC; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5362BE921E7C042700204B31 /* Build configuration list for PBXProject "TableHeaderObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5362BEAC1E7C042700204B31 /* Debug */, + 5362BEAD1E7C042700204B31 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5362BEAE1E7C042700204B31 /* Build configuration list for PBXNativeTarget "TableHeaderObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5362BEAF1E7C042700204B31 /* Debug */, + 5362BEB01E7C042700204B31 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5362BE8F1E7C042700204B31 /* Project object */; +} diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.h b/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.h new file mode 100644 index 0000000..0c8fe76 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.h @@ -0,0 +1,39 @@ +// +// AppDelegate.h +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.m new file mode 100644 index 0000000..eba1f80 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/AppDelegate.m @@ -0,0 +1,38 @@ +// +// AppDelegate.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/Assets.xcassets/AppIcon.appiconset/Contents.json b/TableHeader/TableHeaderObjC/TableHeaderObjC/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/LaunchScreen.storyboard b/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/Main.storyboard b/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/Main.storyboard new file mode 100644 index 0000000..dec5842 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/Base.lproj/Main.storyboard @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.h b/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.h new file mode 100644 index 0000000..70414f1 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.h @@ -0,0 +1,42 @@ +// +// DataCell.h +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface DataCell : UITableViewCell + ++ (NSString *)reuseIdentifier; +- (void)configure:(NSString *)title; + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.m new file mode 100644 index 0000000..40e9941 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/DataCell.m @@ -0,0 +1,54 @@ +// +// DataCell.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#import "DataCell.h" + +@interface DataCell () +@property (weak, nonatomic) IBOutlet UILabel *titleLabel; +@end + +@implementation DataCell + ++ (NSString *)reuseIdentifier { + return NSStringFromClass([self class]); +} + +- (void)configure:(NSString *)title { + self.titleLabel.text = title; + + // Still need to do this manually for iOS 9 + self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; +} + +@end + diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/Info.plist b/TableHeader/TableHeaderObjC/TableHeaderObjC/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.h b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.h new file mode 100644 index 0000000..7dca1fa --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.h @@ -0,0 +1,39 @@ +// +// ListDataSource.h +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +@interface ListDataSource : NSObject +- (instancetype)init:(UITableView *)tableView; +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.m new file mode 100644 index 0000000..a863135 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListDataSource.m @@ -0,0 +1,76 @@ +// +// ListDataSource.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "ListDataSource.h" +#import "DataCell.h" + +@interface ListDataSource () +@property (nonatomic, strong) UITableView *tableView; +@end + +@implementation ListDataSource + +- (instancetype)init:(UITableView *)tableView { + self = [super init]; + if (self) { + self.tableView = tableView; + tableView.dataSource = self; + [tableView reloadData]; + } + return self; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 50; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[DataCell reuseIdentifier] forIndexPath:indexPath]; + [self configure:cell forIndexPath:indexPath]; + return cell; +} + +- (void)configure:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { + if ([cell isKindOfClass:[DataCell class]]) { + DataCell *dataCell = (DataCell *)cell; + NSString *title = [NSString stringWithFormat:@"Title for row %ld",(long)indexPath.row]; + [dataCell configure:title]; + } +} + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.h b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.h new file mode 100644 index 0000000..0219e37 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.h @@ -0,0 +1,39 @@ +// +// ListTableViewController.h +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +@interface ListTableViewController : UITableViewController + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.m new file mode 100644 index 0000000..ed89ea5 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/ListTableViewController.m @@ -0,0 +1,110 @@ +// +// ListTableViewController.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "ListTableViewController.h" +#import "ListDataSource.h" + +@interface ListTableViewController () +@property (nonatomic,strong) ListDataSource *listDataSource; +@end + +@implementation ListTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.listDataSource = [[ListDataSource alloc] init:self.tableView]; + self.tableView.dataSource = self.listDataSource; + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedRowHeight = UITableViewAutomaticDimension; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentSizeDidChange:) name:UIContentSizeCategoryDidChangeNotification object:nil]; +} + +- (void)contentSizeDidChange:(NSNotification *)notification { + [self.tableView reloadData]; +} + +// viewDidLayoutSubviews() +// Called to notify the view controller that its view has just laid out its +// subviews. + +// When the bounds change for a view controller'€™s view, the view adjusts +// the positions of its subviews and then the system calls this method. +// However, this method being called does not indicate that the individual +// layouts of the view'€™s subviews have been adjusted. Each subview is +// responsible for adjusting its own layout. + +// Your view controller can override this method to make changes after the +// view lays out its subviews. + +// The default implementation of this method does nothing. + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + UIView *headerView = self.tableView.tableHeaderView; + if (headerView != nil) { + + // The table view header is created with the frame size set in + // the Storyboard. Calculate the new size and reset the header + // view to trigger the layout. + + // Calculate the minimum height of the header view that allows + // the text label to fit its preferred width. + + CGSize size = [headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + + if (headerView.frame.size.height != size.height) { + CGRect frame = headerView.frame; + frame.size.height = size.height; + headerView.frame = frame; + + // Need to set the header view property of the table view + // to trigger the new layout. Be careful to only do this + // once when the height changes or we get stuck in a layout loop. + + self.tableView.tableHeaderView = headerView; + + // Now that the table view header is sized correctly have + // the table view redo its layout so that the cells are + // correcly positioned for the new header size. + + // This only seems to be necessary on iOS 9. + + [self.tableView layoutIfNeeded]; + } + } +} + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.h b/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.h new file mode 100644 index 0000000..faf7414 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.h @@ -0,0 +1,39 @@ +// +// TextTableHeader.h +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +@import UIKit; + +@interface TextTableHeader : UIView + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.m new file mode 100644 index 0000000..e0f7746 --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/TextTableHeader.m @@ -0,0 +1,53 @@ +// +// TextTableHeader.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "TextTableHeader.h" + +@interface TextTableHeader () +@property (weak, nonatomic) IBOutlet UILabel *titleLabel; +@end + +@implementation TextTableHeader + +- (void)awakeFromNib { + [super awakeFromNib]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentSizeDidChange:) name:UIContentSizeCategoryDidChangeNotification object:nil]; +} + +- (void)contentSizeDidChange:(NSNotification *)notification { + self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleTitle3]; +} + +@end diff --git a/TableHeader/TableHeaderObjC/TableHeaderObjC/main.m b/TableHeader/TableHeaderObjC/TableHeaderObjC/main.m new file mode 100644 index 0000000..b4ccdaf --- /dev/null +++ b/TableHeader/TableHeaderObjC/TableHeaderObjC/main.m @@ -0,0 +1,42 @@ +// +// main.m +// TableHeaderObjC +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/TableHeader/TableHeaderSwift/TableHeader.xcodeproj/project.pbxproj b/TableHeader/TableHeaderSwift/TableHeader.xcodeproj/project.pbxproj new file mode 100644 index 0000000..acbab84 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader.xcodeproj/project.pbxproj @@ -0,0 +1,390 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 53F945981E780436002E1728 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945971E780436002E1728 /* AppDelegate.swift */; }; + 53F9459D1E780436002E1728 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F9459B1E780436002E1728 /* Main.storyboard */; }; + 53F9459F1E780436002E1728 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53F9459E1E780436002E1728 /* Assets.xcassets */; }; + 53F945A21E780436002E1728 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53F945A01E780436002E1728 /* LaunchScreen.storyboard */; }; + 53F945AD1E7805AB002E1728 /* ListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945AC1E7805AB002E1728 /* ListTableViewController.swift */; }; + 53F945B01E7805E8002E1728 /* ListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945AF1E7805E8002E1728 /* ListDataSource.swift */; }; + 53F945B21E7806F6002E1728 /* DataCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945B11E7806F6002E1728 /* DataCell.swift */; }; + 53F945B51E780713002E1728 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945B31E780713002E1728 /* ConfigurableCell.swift */; }; + 53F945B61E780713002E1728 /* ReusableIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945B41E780713002E1728 /* ReusableIdentifier.swift */; }; + 53F945B91E780AE3002E1728 /* TextTableHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F945B81E780AE3002E1728 /* TextTableHeader.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53F945941E780436002E1728 /* TableHeader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TableHeader.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53F945971E780436002E1728 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53F9459C1E780436002E1728 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53F9459E1E780436002E1728 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53F945A11E780436002E1728 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53F945A31E780436002E1728 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53F945AC1E7805AB002E1728 /* ListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTableViewController.swift; sourceTree = ""; }; + 53F945AF1E7805E8002E1728 /* ListDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListDataSource.swift; sourceTree = ""; }; + 53F945B11E7806F6002E1728 /* DataCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataCell.swift; sourceTree = ""; }; + 53F945B31E780713002E1728 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; + 53F945B41E780713002E1728 /* ReusableIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableIdentifier.swift; sourceTree = ""; }; + 53F945B81E780AE3002E1728 /* TextTableHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTableHeader.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53F945911E780436002E1728 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53F9458B1E780436002E1728 = { + isa = PBXGroup; + children = ( + 53F945961E780436002E1728 /* TableHeader */, + 53F945951E780436002E1728 /* Products */, + ); + sourceTree = ""; + }; + 53F945951E780436002E1728 /* Products */ = { + isa = PBXGroup; + children = ( + 53F945941E780436002E1728 /* TableHeader.app */, + ); + name = Products; + sourceTree = ""; + }; + 53F945961E780436002E1728 /* TableHeader */ = { + isa = PBXGroup; + children = ( + 53F945B71E780719002E1728 /* Protocols and Extensions */, + 53F945A91E780562002E1728 /* Delegates */, + 53F945AE1E7805B6002E1728 /* Controllers */, + 53F945AA1E780570002E1728 /* Views */, + 53F945AB1E780583002E1728 /* Supporting Files */, + ); + path = TableHeader; + sourceTree = ""; + }; + 53F945A91E780562002E1728 /* Delegates */ = { + isa = PBXGroup; + children = ( + 53F945971E780436002E1728 /* AppDelegate.swift */, + 53F945AF1E7805E8002E1728 /* ListDataSource.swift */, + ); + name = Delegates; + sourceTree = ""; + }; + 53F945AA1E780570002E1728 /* Views */ = { + isa = PBXGroup; + children = ( + 53F945B11E7806F6002E1728 /* DataCell.swift */, + 53F945A01E780436002E1728 /* LaunchScreen.storyboard */, + 53F9459B1E780436002E1728 /* Main.storyboard */, + 53F945B81E780AE3002E1728 /* TextTableHeader.swift */, + ); + name = Views; + sourceTree = ""; + }; + 53F945AB1E780583002E1728 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 53F9459E1E780436002E1728 /* Assets.xcassets */, + 53F945A31E780436002E1728 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 53F945AE1E7805B6002E1728 /* Controllers */ = { + isa = PBXGroup; + children = ( + 53F945AC1E7805AB002E1728 /* ListTableViewController.swift */, + ); + name = Controllers; + sourceTree = ""; + }; + 53F945B71E780719002E1728 /* Protocols and Extensions */ = { + isa = PBXGroup; + children = ( + 53F945B31E780713002E1728 /* ConfigurableCell.swift */, + 53F945B41E780713002E1728 /* ReusableIdentifier.swift */, + ); + name = "Protocols and Extensions"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53F945931E780436002E1728 /* TableHeader */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53F945A61E780436002E1728 /* Build configuration list for PBXNativeTarget "TableHeader" */; + buildPhases = ( + 53F945901E780436002E1728 /* Sources */, + 53F945911E780436002E1728 /* Frameworks */, + 53F945921E780436002E1728 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TableHeader; + productName = TableHeader; + productReference = 53F945941E780436002E1728 /* TableHeader.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53F9458C1E780436002E1728 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0820; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53F945931E780436002E1728 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = LCC2J94N44; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53F9458F1E780436002E1728 /* Build configuration list for PBXProject "TableHeader" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53F9458B1E780436002E1728; + productRefGroup = 53F945951E780436002E1728 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53F945931E780436002E1728 /* TableHeader */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53F945921E780436002E1728 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F945A21E780436002E1728 /* LaunchScreen.storyboard in Resources */, + 53F9459F1E780436002E1728 /* Assets.xcassets in Resources */, + 53F9459D1E780436002E1728 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53F945901E780436002E1728 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53F945B51E780713002E1728 /* ConfigurableCell.swift in Sources */, + 53F945B61E780713002E1728 /* ReusableIdentifier.swift in Sources */, + 53F945981E780436002E1728 /* AppDelegate.swift in Sources */, + 53F945B91E780AE3002E1728 /* TextTableHeader.swift in Sources */, + 53F945B01E7805E8002E1728 /* ListDataSource.swift in Sources */, + 53F945AD1E7805AB002E1728 /* ListTableViewController.swift in Sources */, + 53F945B21E7806F6002E1728 /* DataCell.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53F9459B1E780436002E1728 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F9459C1E780436002E1728 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53F945A01E780436002E1728 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53F945A11E780436002E1728 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53F945A41E780436002E1728 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53F945A51E780436002E1728 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53F945A71E780436002E1728 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = TableHeader/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TableHeader; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 53F945A81E780436002E1728 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = TableHeader/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.TableHeader; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53F9458F1E780436002E1728 /* Build configuration list for PBXProject "TableHeader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F945A41E780436002E1728 /* Debug */, + 53F945A51E780436002E1728 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53F945A61E780436002E1728 /* Build configuration list for PBXNativeTarget "TableHeader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53F945A71E780436002E1728 /* Debug */, + 53F945A81E780436002E1728 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53F9458C1E780436002E1728 /* Project object */; +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/AppDelegate.swift b/TableHeader/TableHeaderSwift/TableHeader/AppDelegate.swift new file mode 100644 index 0000000..b76494e --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// TableHeader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/Assets.xcassets/AppIcon.appiconset/Contents.json b/TableHeader/TableHeaderSwift/TableHeader/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/LaunchScreen.storyboard b/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/Main.storyboard b/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/Main.storyboard new file mode 100644 index 0000000..25ef409 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/Base.lproj/Main.storyboard @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TableHeader/TableHeaderSwift/TableHeader/ConfigurableCell.swift b/TableHeader/TableHeaderSwift/TableHeader/ConfigurableCell.swift new file mode 100644 index 0000000..eced6d5 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/ConfigurableCell.swift @@ -0,0 +1,38 @@ +// +// ConfigurableCell.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ConfigurableCell { + associatedtype Object + func configure(object: Object) +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/DataCell.swift b/TableHeader/TableHeaderSwift/TableHeader/DataCell.swift new file mode 100644 index 0000000..b5a0bad --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/DataCell.swift @@ -0,0 +1,54 @@ +// +// DataCell.swift +// AdjustScroll +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +class DataCell: UITableViewCell, ReusableIdentifier { + @IBOutlet fileprivate var title: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + if #available(iOS 10.0, *) { + title.adjustsFontForContentSizeCategory = true + } + } +} + +extension DataCell: ConfigurableCell { + func configure(object: String) { + title.text = object + + // Still need to do this manually for iOS 9 + title.font = UIFont.preferredFont(forTextStyle: .body) + } +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/Info.plist b/TableHeader/TableHeaderSwift/TableHeader/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/TableHeader/TableHeaderSwift/TableHeader/ListDataSource.swift b/TableHeader/TableHeaderSwift/TableHeader/ListDataSource.swift new file mode 100644 index 0000000..d59f1b2 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/ListDataSource.swift @@ -0,0 +1,67 @@ +// +// ListDataSource.swift +// TableHeader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ListDataSource: NSObject { + private let tableView: UITableView + + init(tableView: UITableView) { + self.tableView = tableView + super.init() + tableView.dataSource = self + tableView.reloadData() + } +} + +extension ListDataSource: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 50 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: DataCell.reuseIdentifier, for: indexPath) + configure(cell: cell, indexPath: indexPath) + return cell + } + + private func configure(cell: UITableViewCell, indexPath: IndexPath) { + if let cell = cell as? DataCell { + cell.configure(object: "Title for row \(indexPath.row)") + } + } +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/ListTableViewController.swift b/TableHeader/TableHeaderSwift/TableHeader/ListTableViewController.swift new file mode 100644 index 0000000..1f4a1ff --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/ListTableViewController.swift @@ -0,0 +1,108 @@ +// +// ListTableViewController.swift +// TableHeader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class ListTableViewController: UITableViewController { + private var listDataSource: ListDataSource? + + override func viewDidLoad() { + super.viewDidLoad() + listDataSource = ListDataSource(tableView: tableView) + tableView.dataSource = listDataSource + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = UITableView.automaticDimension + + guard #available(iOS 10.0, *) else { + // Manually observe the UIContentSizeCategoryDidChange + // notification for iOS 9. + + NotificationCenter.default.addObserver(self, selector: #selector(contentSizeDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) + return + } + } + + @objc private func contentSizeDidChange(_ notification: NSNotification) { + tableView.reloadData() + } + + // viewDidLayoutSubviews() + // Called to notify the view controller that its view has just laid out its + // subviews. + + // When the bounds change for a view controller'€™s view, the view adjusts + // the positions of its subviews and then the system calls this method. + // However, this method being called does not indicate that the individual + // layouts of the view'€™s subviews have been adjusted. Each subview is + // responsible for adjusting its own layout. + + // Your view controller can override this method to make changes after the + // view lays out its subviews. + + // The default implementation of this method does nothing. + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + guard let headerView = tableView.tableHeaderView else { + return + } + + // The table view header is created with the frame size set in + // the Storyboard. Calculate the new size and reset the header + // view to trigger the layout. + + // Calculate the minimum height of the header view that allows + // the text label to fit its preferred width. + + let size = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + + if headerView.frame.size.height != size.height { + headerView.frame.size.height = size.height + + // Need to set the header view property of the table view + // to trigger the new layout. Be careful to only do this + // once when the height changes or we get stuck in a layout loop. + + tableView.tableHeaderView = headerView + + // Now that the table view header is sized correctly have + // the table view redo its layout so that the cells are + // correcly positioned for the new header size. + + // This only seems to be necessary on iOS 9. + + tableView.layoutIfNeeded() + } + } +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/ReusableIdentifier.swift b/TableHeader/TableHeaderSwift/TableHeader/ReusableIdentifier.swift new file mode 100644 index 0000000..893e7f4 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/ReusableIdentifier.swift @@ -0,0 +1,43 @@ +// +// ReusableIdentifier.swift +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2016-2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +protocol ReusableIdentifier: class { + static var reuseIdentifier: String { get } +} + +extension ReusableIdentifier { + static var reuseIdentifier: String { + return "\(self)" + } +} diff --git a/TableHeader/TableHeaderSwift/TableHeader/TextTableHeader.swift b/TableHeader/TableHeaderSwift/TableHeader/TextTableHeader.swift new file mode 100644 index 0000000..24ff3f9 --- /dev/null +++ b/TableHeader/TableHeaderSwift/TableHeader/TextTableHeader.swift @@ -0,0 +1,52 @@ +// +// TextTableHeader.swift +// TableHeader +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class TextTableHeader: UIView { + @IBOutlet private var title: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + if #available(iOS 10.0, *) { + title.adjustsFontForContentSizeCategory = true + } else { + NotificationCenter.default.addObserver(self, selector: #selector(contentSizeDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil) + } + } + + // Still need to do this manually for iOS 9 + @objc private func contentSizeDidChange(_ notification: NSNotification) { + title.font = UIFont.preferredFont(forTextStyle: .title3) + } +} diff --git a/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPad.xib b/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPad.xib deleted file mode 100644 index 3948b16..0000000 --- a/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPad.xib +++ /dev/null @@ -1,166 +0,0 @@ - - - - 1296 - 11D50 - 2182 - 1138.32 - 568.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - {{0, 20}, {320, 832}} - - - - 3 - MQA - - YES - - 2 - - - IBUISplitViewMasterSimulatedSizeMetrics - - YES - - - - - - {320, 852} - {320, 768} - - - IBIPadFramework - Master - IBUISplitViewController - - IBUISplitViewControllerContentSizeLocation - IBUISplitViewControllerContentSizeLocationMaster - - - IBIPadFramework - YES - 1 - 0 - YES - 56 - 22 - 22 - - - - - - - view - - - - 3 - - - - dataSource - - - - 4 - - - - delegate - - - - 5 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - UYLTaskListViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 5 - - - - - UYLTaskListViewController - UITableViewController - - IBProjectSource - ./Classes/UYLTaskListViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - diff --git a/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPhone.xib b/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPhone.xib deleted file mode 100644 index 0087cf4..0000000 --- a/TaskTimer/TaskTimer/en.lproj/UYLTaskListViewController_iPhone.xib +++ /dev/null @@ -1,143 +0,0 @@ - - - - 1296 - 11D50 - 2182 - 1138.32 - 568.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - {{0, 20}, {320, 460}} - - - - 3 - MQA - - YES - - IBCocoaTouchFramework - YES - 1 - 0 - YES - 56 - 22 - 22 - - - - - - - view - - - - 3 - - - - dataSource - - - - 4 - - - - delegate - - - - 5 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - UYLTaskListViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 5 - - - - - UYLTaskListViewController - UITableViewController - - IBProjectSource - ./Classes/UYLTaskListViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - diff --git a/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPad.xib b/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPad.xib deleted file mode 100644 index 0fc013c..0000000 --- a/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPad.xib +++ /dev/null @@ -1,331 +0,0 @@ - - - - 1296 - 11E53 - 2182 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBUIButton - IBUIView - IBUITextField - IBProxyObject - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - - - - 290 - {{20, 95}, {728, 31}} - - - - _NS:9 - NO - YES - IBIPadFramework - 0 - - 3 - - 3 - MAA - - 2 - - - YES - 17 - - 2 - 9 - YES - IBCocoaTouchFramework - - 1 - - 1 - 14 - - - Helvetica - 14 - 16 - - - - - 290 - {{20, 176}, {728, 174}} - - - _NS:9 - - 3 - MC42NjY2NjY2NjY3AA - - 3 - IBIPadFramework - - - - -2147483355 - {{314, 462}, {140, 37}} - - - _NS:9 - NO - - Reset - - IBIPadFramework - 0 - 0 - Reset - - 3 - MQA - - - 1 - MSAxIDEAA - - - 3 - MC41AA - - - NSImage - redbutton.png - - - 2 - 2 - - - Helvetica-Bold - 18 - 16 - - - - {{0, 64}, {768, 960}} - - - - - NO - - 2 - - - NO - - IBIPadFramework - - - - - - - view - - - - 12 - - - - taskNote - - - - 69 - - - - taskCounterView - - - - 72 - - - - taskResetButton - - - - 87 - - - - delegate - - - - 68 - - - - taskResetAction - - - 7 - - 88 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 8 - - - - - - - - - - 67 - - - - - 70 - - - - - - 86 - - - - - - - UYLTaskViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UYLCounterView - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - - 88 - - - - - UYLCounterView - UIView - - IBProjectSource - ./Classes/UYLCounterView.h - - - - UYLTaskViewController - UIViewController - - taskResetAction - id - - - taskResetAction - - taskResetAction - id - - - - UYLCounterView - UITextField - UIButton - - - - taskCounterView - UYLCounterView - - - taskNote - UITextField - - - taskResetButton - UIButton - - - - IBProjectSource - ./Classes/UYLTaskViewController.h - - - - - 0 - IBIPadFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - - redbutton.png - {140, 40} - - 1181 - - diff --git a/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPhone.xib b/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPhone.xib deleted file mode 100644 index d65f751..0000000 --- a/TaskTimer/TaskTimer/en.lproj/UYLTaskViewController_iPhone.xib +++ /dev/null @@ -1,334 +0,0 @@ - - - - 1296 - 11E53 - 2182 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBUIButton - IBUIView - IBUITextField - IBProxyObject - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 290 - {{20, 59}, {280, 60}} - - - - _NS:9 - - 3 - MC42NjY2NjY2NjY3AA - - 3 - IBCocoaTouchFramework - - - - 290 - {{20, 18}, {280, 31}} - - - - _NS:9 - NO - YES - IBCocoaTouchFramework - 0 - - 3 - Enter task description - - 3 - MAA - - 2 - - - YES - 17 - - 2 - 9 - YES - IBCocoaTouchFramework - - 1 - - 1 - 14 - - - Helvetica - 14 - 16 - - - - - -2147483355 - {{90, 140}, {140, 37}} - - - _NS:9 - NO - - Reset - - IBCocoaTouchFramework - 0 - 0 - Reset - - 3 - MQA - - - 1 - MSAxIDEAA - - - 3 - MC41AA - - - NSImage - redbutton.png - - - 2 - 2 - - - Helvetica-Bold - 18 - 16 - - - - {{0, 64}, {320, 416}} - - - - - 3 - MQA - - - - - NO - - IBCocoaTouchFramework - - - - - - - view - - - - 3 - - - - taskNote - - - - 20 - - - - taskCounterView - - - - 23 - - - - taskResetButton - - - - 39 - - - - delegate - - - - 22 - - - - taskResetAction - - - 7 - - 40 - - - - - - 0 - - - - - - 1 - - - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 17 - - - - - - 19 - - - - - 38 - - - - - - - UYLTaskViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UYLCounterView - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - - 40 - - - - - UYLCounterView - UIView - - IBProjectSource - ./Classes/UYLCounterView.h - - - - UYLTaskViewController - UIViewController - - taskResetAction - id - - - taskResetAction - - taskResetAction - id - - - - UYLCounterView - UITextField - UIButton - - - - taskCounterView - UYLCounterView - - - taskNote - UITextField - - - taskResetButton - UIButton - - - - IBProjectSource - ./Classes/UYLTaskViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - - redbutton.png - {140, 40} - - 1181 - - diff --git a/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj b/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj deleted file mode 100644 index 7c0a765..0000000 --- a/TwitterSearch/TwitterSearch.xcodeproj/project.pbxproj +++ /dev/null @@ -1,391 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 53CB80FE139D70FF0030ADD7 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB80FD139D70FF0030ADD7 /* UIKit.framework */; }; - 53CB8100139D70FF0030ADD7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB80FF139D70FF0030ADD7 /* Foundation.framework */; }; - 53CB8102139D70FF0030ADD7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */; }; - 53CB8108139D70FF0030ADD7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */; }; - 53CB810B139D70FF0030ADD7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB810A139D70FF0030ADD7 /* main.m */; }; - 53CB810E139D70FF0030ADD7 /* TwitterSearchAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */; }; - 53CB8111139D70FF0030ADD7 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53CB810F139D70FF0030ADD7 /* MainWindow.xib */; }; - 53CB8114139D70FF0030ADD7 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8113139D70FF0030ADD7 /* RootViewController.m */; }; - 53CB8117139D70FF0030ADD7 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53CB8115139D70FF0030ADD7 /* RootViewController.xib */; }; - 53CB812B139D73810030ADD7 /* SearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB812A139D73810030ADD7 /* SearchViewController.m */; }; - 53CB812D139D73C00030ADD7 /* SearchViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53CB812C139D73C00030ADD7 /* SearchViewController.xib */; }; - 53CB814F139D74B20030ADD7 /* NSObject+SBJson.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8137139D74B20030ADD7 /* NSObject+SBJson.m */; }; - 53CB8150139D74B20030ADD7 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB813A139D74B20030ADD7 /* SBJsonParser.m */; }; - 53CB8151139D74B20030ADD7 /* SBJsonStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB813C139D74B20030ADD7 /* SBJsonStreamParser.m */; }; - 53CB8152139D74B20030ADD7 /* SBJsonStreamParserAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB813E139D74B20030ADD7 /* SBJsonStreamParserAccumulator.m */; }; - 53CB8153139D74B20030ADD7 /* SBJsonStreamParserAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8140139D74B20030ADD7 /* SBJsonStreamParserAdapter.m */; }; - 53CB8154139D74B20030ADD7 /* SBJsonStreamParserState.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8142139D74B20030ADD7 /* SBJsonStreamParserState.m */; }; - 53CB8155139D74B20030ADD7 /* SBJsonStreamWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8144139D74B20030ADD7 /* SBJsonStreamWriter.m */; }; - 53CB8156139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8146139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.m */; }; - 53CB8157139D74B20030ADD7 /* SBJsonStreamWriterState.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB8148139D74B20030ADD7 /* SBJsonStreamWriterState.m */; }; - 53CB8158139D74B20030ADD7 /* SBJsonTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB814A139D74B20030ADD7 /* SBJsonTokeniser.m */; }; - 53CB8159139D74B20030ADD7 /* SBJsonUTF8Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB814C139D74B20030ADD7 /* SBJsonUTF8Stream.m */; }; - 53CB815A139D74B20030ADD7 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CB814E139D74B20030ADD7 /* SBJsonWriter.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TwitterSearch.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 53CB80FD139D70FF0030ADD7 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 53CB80FF139D70FF0030ADD7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 53CB8105139D70FF0030ADD7 /* TwitterSearch-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TwitterSearch-Info.plist"; sourceTree = ""; }; - 53CB8107139D70FF0030ADD7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 53CB8109139D70FF0030ADD7 /* TwitterSearch-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TwitterSearch-Prefix.pch"; sourceTree = ""; }; - 53CB810A139D70FF0030ADD7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 53CB810C139D70FF0030ADD7 /* TwitterSearchAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TwitterSearchAppDelegate.h; sourceTree = ""; }; - 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TwitterSearchAppDelegate.m; sourceTree = ""; }; - 53CB8110139D70FF0030ADD7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; - 53CB8112139D70FF0030ADD7 /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; - 53CB8113139D70FF0030ADD7 /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; - 53CB8116139D70FF0030ADD7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/RootViewController.xib; sourceTree = ""; }; - 53CB8129139D73800030ADD7 /* SearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchViewController.h; sourceTree = ""; }; - 53CB812A139D73810030ADD7 /* SearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchViewController.m; sourceTree = ""; }; - 53CB812C139D73C00030ADD7 /* SearchViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchViewController.xib; sourceTree = ""; }; - 53CB8135139D74B20030ADD7 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; - 53CB8136139D74B20030ADD7 /* NSObject+SBJson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJson.h"; sourceTree = ""; }; - 53CB8137139D74B20030ADD7 /* NSObject+SBJson.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJson.m"; sourceTree = ""; }; - 53CB8138139D74B20030ADD7 /* SBJson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson.h; sourceTree = ""; }; - 53CB8139139D74B20030ADD7 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; - 53CB813A139D74B20030ADD7 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; - 53CB813B139D74B20030ADD7 /* SBJsonStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParser.h; sourceTree = ""; }; - 53CB813C139D74B20030ADD7 /* SBJsonStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParser.m; sourceTree = ""; }; - 53CB813D139D74B20030ADD7 /* SBJsonStreamParserAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserAccumulator.h; sourceTree = ""; }; - 53CB813E139D74B20030ADD7 /* SBJsonStreamParserAccumulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserAccumulator.m; sourceTree = ""; }; - 53CB813F139D74B20030ADD7 /* SBJsonStreamParserAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserAdapter.h; sourceTree = ""; }; - 53CB8140139D74B20030ADD7 /* SBJsonStreamParserAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserAdapter.m; sourceTree = ""; }; - 53CB8141139D74B20030ADD7 /* SBJsonStreamParserState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserState.h; sourceTree = ""; }; - 53CB8142139D74B20030ADD7 /* SBJsonStreamParserState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserState.m; sourceTree = ""; }; - 53CB8143139D74B20030ADD7 /* SBJsonStreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriter.h; sourceTree = ""; }; - 53CB8144139D74B20030ADD7 /* SBJsonStreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriter.m; sourceTree = ""; }; - 53CB8145139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriterAccumulator.h; sourceTree = ""; }; - 53CB8146139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriterAccumulator.m; sourceTree = ""; }; - 53CB8147139D74B20030ADD7 /* SBJsonStreamWriterState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriterState.h; sourceTree = ""; }; - 53CB8148139D74B20030ADD7 /* SBJsonStreamWriterState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriterState.m; sourceTree = ""; }; - 53CB8149139D74B20030ADD7 /* SBJsonTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonTokeniser.h; sourceTree = ""; }; - 53CB814A139D74B20030ADD7 /* SBJsonTokeniser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonTokeniser.m; sourceTree = ""; }; - 53CB814B139D74B20030ADD7 /* SBJsonUTF8Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonUTF8Stream.h; sourceTree = ""; }; - 53CB814C139D74B20030ADD7 /* SBJsonUTF8Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonUTF8Stream.m; sourceTree = ""; }; - 53CB814D139D74B20030ADD7 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; - 53CB814E139D74B20030ADD7 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 53CB80F6139D70FF0030ADD7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 53CB80FE139D70FF0030ADD7 /* UIKit.framework in Frameworks */, - 53CB8100139D70FF0030ADD7 /* Foundation.framework in Frameworks */, - 53CB8102139D70FF0030ADD7 /* CoreGraphics.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 53CB80EE139D70FF0030ADD7 = { - isa = PBXGroup; - children = ( - 53CB8103139D70FF0030ADD7 /* TwitterSearch */, - 53CB80FC139D70FF0030ADD7 /* Frameworks */, - 53CB80FA139D70FF0030ADD7 /* Products */, - ); - sourceTree = ""; - }; - 53CB80FA139D70FF0030ADD7 /* Products */ = { - isa = PBXGroup; - children = ( - 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */, - ); - name = Products; - sourceTree = ""; - }; - 53CB80FC139D70FF0030ADD7 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 53CB80FD139D70FF0030ADD7 /* UIKit.framework */, - 53CB80FF139D70FF0030ADD7 /* Foundation.framework */, - 53CB8101139D70FF0030ADD7 /* CoreGraphics.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 53CB8103139D70FF0030ADD7 /* TwitterSearch */ = { - isa = PBXGroup; - children = ( - 53CB8134139D74B20030ADD7 /* JSON */, - 53CB810C139D70FF0030ADD7 /* TwitterSearchAppDelegate.h */, - 53CB810D139D70FF0030ADD7 /* TwitterSearchAppDelegate.m */, - 53CB8112139D70FF0030ADD7 /* RootViewController.h */, - 53CB8113139D70FF0030ADD7 /* RootViewController.m */, - 53CB8129139D73800030ADD7 /* SearchViewController.h */, - 53CB812A139D73810030ADD7 /* SearchViewController.m */, - 53CB815C139D75DB0030ADD7 /* Resources */, - 53CB8104139D70FF0030ADD7 /* Supporting Files */, - ); - path = TwitterSearch; - sourceTree = ""; - }; - 53CB8104139D70FF0030ADD7 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 53CB8105139D70FF0030ADD7 /* TwitterSearch-Info.plist */, - 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */, - 53CB8109139D70FF0030ADD7 /* TwitterSearch-Prefix.pch */, - 53CB810A139D70FF0030ADD7 /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 53CB8134139D74B20030ADD7 /* JSON */ = { - isa = PBXGroup; - children = ( - 53CB8135139D74B20030ADD7 /* JSON.h */, - 53CB8136139D74B20030ADD7 /* NSObject+SBJson.h */, - 53CB8137139D74B20030ADD7 /* NSObject+SBJson.m */, - 53CB8138139D74B20030ADD7 /* SBJson.h */, - 53CB8139139D74B20030ADD7 /* SBJsonParser.h */, - 53CB813A139D74B20030ADD7 /* SBJsonParser.m */, - 53CB813B139D74B20030ADD7 /* SBJsonStreamParser.h */, - 53CB813C139D74B20030ADD7 /* SBJsonStreamParser.m */, - 53CB813D139D74B20030ADD7 /* SBJsonStreamParserAccumulator.h */, - 53CB813E139D74B20030ADD7 /* SBJsonStreamParserAccumulator.m */, - 53CB813F139D74B20030ADD7 /* SBJsonStreamParserAdapter.h */, - 53CB8140139D74B20030ADD7 /* SBJsonStreamParserAdapter.m */, - 53CB8141139D74B20030ADD7 /* SBJsonStreamParserState.h */, - 53CB8142139D74B20030ADD7 /* SBJsonStreamParserState.m */, - 53CB8143139D74B20030ADD7 /* SBJsonStreamWriter.h */, - 53CB8144139D74B20030ADD7 /* SBJsonStreamWriter.m */, - 53CB8145139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.h */, - 53CB8146139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.m */, - 53CB8147139D74B20030ADD7 /* SBJsonStreamWriterState.h */, - 53CB8148139D74B20030ADD7 /* SBJsonStreamWriterState.m */, - 53CB8149139D74B20030ADD7 /* SBJsonTokeniser.h */, - 53CB814A139D74B20030ADD7 /* SBJsonTokeniser.m */, - 53CB814B139D74B20030ADD7 /* SBJsonUTF8Stream.h */, - 53CB814C139D74B20030ADD7 /* SBJsonUTF8Stream.m */, - 53CB814D139D74B20030ADD7 /* SBJsonWriter.h */, - 53CB814E139D74B20030ADD7 /* SBJsonWriter.m */, - ); - path = JSON; - sourceTree = ""; - }; - 53CB815C139D75DB0030ADD7 /* Resources */ = { - isa = PBXGroup; - children = ( - 53CB810F139D70FF0030ADD7 /* MainWindow.xib */, - 53CB8115139D70FF0030ADD7 /* RootViewController.xib */, - 53CB812C139D73C00030ADD7 /* SearchViewController.xib */, - ); - name = Resources; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 53CB80F8139D70FF0030ADD7 /* TwitterSearch */ = { - isa = PBXNativeTarget; - buildConfigurationList = 53CB811A139D70FF0030ADD7 /* Build configuration list for PBXNativeTarget "TwitterSearch" */; - buildPhases = ( - 53CB80F5139D70FF0030ADD7 /* Sources */, - 53CB80F6139D70FF0030ADD7 /* Frameworks */, - 53CB80F7139D70FF0030ADD7 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = TwitterSearch; - productName = TwitterSearch; - productReference = 53CB80F9139D70FF0030ADD7 /* TwitterSearch.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 53CB80F0139D70FF0030ADD7 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0420; - }; - buildConfigurationList = 53CB80F3139D70FF0030ADD7 /* Build configuration list for PBXProject "TwitterSearch" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 53CB80EE139D70FF0030ADD7; - productRefGroup = 53CB80FA139D70FF0030ADD7 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 53CB80F8139D70FF0030ADD7 /* TwitterSearch */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 53CB80F7139D70FF0030ADD7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 53CB8108139D70FF0030ADD7 /* InfoPlist.strings in Resources */, - 53CB8111139D70FF0030ADD7 /* MainWindow.xib in Resources */, - 53CB8117139D70FF0030ADD7 /* RootViewController.xib in Resources */, - 53CB812D139D73C00030ADD7 /* SearchViewController.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 53CB80F5139D70FF0030ADD7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 53CB810B139D70FF0030ADD7 /* main.m in Sources */, - 53CB810E139D70FF0030ADD7 /* TwitterSearchAppDelegate.m in Sources */, - 53CB8114139D70FF0030ADD7 /* RootViewController.m in Sources */, - 53CB812B139D73810030ADD7 /* SearchViewController.m in Sources */, - 53CB814F139D74B20030ADD7 /* NSObject+SBJson.m in Sources */, - 53CB8150139D74B20030ADD7 /* SBJsonParser.m in Sources */, - 53CB8151139D74B20030ADD7 /* SBJsonStreamParser.m in Sources */, - 53CB8152139D74B20030ADD7 /* SBJsonStreamParserAccumulator.m in Sources */, - 53CB8153139D74B20030ADD7 /* SBJsonStreamParserAdapter.m in Sources */, - 53CB8154139D74B20030ADD7 /* SBJsonStreamParserState.m in Sources */, - 53CB8155139D74B20030ADD7 /* SBJsonStreamWriter.m in Sources */, - 53CB8156139D74B20030ADD7 /* SBJsonStreamWriterAccumulator.m in Sources */, - 53CB8157139D74B20030ADD7 /* SBJsonStreamWriterState.m in Sources */, - 53CB8158139D74B20030ADD7 /* SBJsonTokeniser.m in Sources */, - 53CB8159139D74B20030ADD7 /* SBJsonUTF8Stream.m in Sources */, - 53CB815A139D74B20030ADD7 /* SBJsonWriter.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 53CB8106139D70FF0030ADD7 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 53CB8107139D70FF0030ADD7 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 53CB810F139D70FF0030ADD7 /* MainWindow.xib */ = { - isa = PBXVariantGroup; - children = ( - 53CB8110139D70FF0030ADD7 /* en */, - ); - name = MainWindow.xib; - sourceTree = ""; - }; - 53CB8115139D70FF0030ADD7 /* RootViewController.xib */ = { - isa = PBXVariantGroup; - children = ( - 53CB8116139D70FF0030ADD7 /* en */, - ); - name = RootViewController.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 53CB8118139D70FF0030ADD7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 53CB8119139D70FF0030ADD7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - SDKROOT = iphoneos; - }; - name = Release; - }; - 53CB811B139D70FF0030ADD7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "TwitterSearch/TwitterSearch-Prefix.pch"; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INFOPLIST_FILE = "TwitterSearch/TwitterSearch-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 53CB811C139D70FF0030ADD7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COPY_PHASE_STRIP = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "TwitterSearch/TwitterSearch-Prefix.pch"; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INFOPLIST_FILE = "TwitterSearch/TwitterSearch-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - VALIDATE_PRODUCT = YES; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 53CB80F3139D70FF0030ADD7 /* Build configuration list for PBXProject "TwitterSearch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 53CB8118139D70FF0030ADD7 /* Debug */, - 53CB8119139D70FF0030ADD7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 53CB811A139D70FF0030ADD7 /* Build configuration list for PBXNativeTarget "TwitterSearch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 53CB811B139D70FF0030ADD7 /* Debug */, - 53CB811C139D70FF0030ADD7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 53CB80F0139D70FF0030ADD7 /* Project object */; -} diff --git a/TwitterSearch/TwitterSearch/JSON/JSON.h b/TwitterSearch/TwitterSearch/JSON/JSON.h deleted file mode 100755 index a2c23fb..0000000 --- a/TwitterSearch/TwitterSearch/JSON/JSON.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// JSON.h -// SBJson -// -// Created by Stig Brautaset on 01/06/2011. -// Copyright 2011 Stig Brautaset. All rights reserved. -// - -#warning The JSON.h header is deprecated, and will disappear in a future release. Please change to include SBJson.h instead. -#include "SBJson.h" \ No newline at end of file diff --git a/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.h b/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.h deleted file mode 100755 index 4c92454..0000000 --- a/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -#pragma mark JSON Writing - -/// Adds JSON generation to NSObject -@interface NSObject (NSObject_SBJsonWriting) - -/** - @brief Encodes the receiver into a JSON string - - Although defined as a category on NSObject it is only defined for NSArray and NSDictionary. - - @return the receiver encoded in JSON, or nil on error. - - @see @ref objc2json - */ -- (NSString *)JSONRepresentation; - -@end - - -#pragma mark JSON Parsing - -/// Adds JSON parsing methods to NSString -@interface NSString (NSString_SBJsonParsing) - -/** - @brief Decodes the receiver's JSON text - - @return the NSDictionary or NSArray represented by the receiver, or nil on error. - - @see @ref json2objc - */ -- (id)JSONValue; - -@end - - diff --git a/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.m b/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.m deleted file mode 100755 index 9d6396d..0000000 --- a/TwitterSearch/TwitterSearch/JSON/NSObject+SBJson.m +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "NSObject+SBJson.h" -#import "SBJsonWriter.h" -#import "SBJsonParser.h" - -@implementation NSObject (NSObject_SBJsonWriting) - -- (NSString *)JSONRepresentation { - SBJsonWriter *writer = [[[SBJsonWriter alloc] init] autorelease]; - NSString *json = [writer stringWithObject:self]; - if (!json) - NSLog(@"-JSONRepresentation failed. Error is: %@", writer.error); - return json; -} - -@end - - - -@implementation NSString (NSString_SBJsonParsing) - -- (id)JSONValue { - SBJsonParser *parser = [[[SBJsonParser alloc] init] autorelease]; - id repr = [parser objectWithString:self]; - if (!repr) - NSLog(@"-JSONValue failed. Error is: %@", parser.error); - return repr; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJson.h b/TwitterSearch/TwitterSearch/JSON/SBJson.h deleted file mode 100755 index b25da4a..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJson.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright (C) 2009-2011 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @page json2objc JSON to Objective-C - - JSON is mapped to Objective-C types in the following way: - - @li null -> NSNull - @li string -> NSString - @li array -> NSMutableArray - @li object -> NSMutableDictionary - @li true -> NSNumber's -numberWithBool:YES - @li false -> NSNumber's -numberWithBool:NO - @li integer up to 19 digits -> NSNumber's -numberWithLongLong: - @li all other numbers -> NSDecimalNumber - - Since Objective-C doesn't have a dedicated class for boolean values, - these turns into NSNumber instances. However, since these are - initialised with the -initWithBool: method they round-trip back to JSON - properly. In other words, they won't silently suddenly become 0 or 1; - they'll be represented as 'true' and 'false' again. - - As an optimisation integers up to 19 digits in length (the max length - for signed long long integers) turn into NSNumber instances, while - complex ones turn into NSDecimalNumber instances. We can thus avoid any - loss of precision as JSON allows ridiculously large numbers. - - @page objc2json Objective-C to JSON - - Objective-C types are mapped to JSON types in the following way: - - @li NSNull -> null - @li NSString -> string - @li NSArray -> array - @li NSDictionary -> object - @li NSNumber's -initWithBool:YES -> true - @li NSNumber's -initWithBool:NO -> false - @li NSNumber -> number - - @note In JSON the keys of an object must be strings. NSDictionary - keys need not be, but attempting to convert an NSDictionary with - non-string keys into JSON will throw an exception. - - NSNumber instances created with the -numberWithBool: method are - converted into the JSON boolean "true" and "false" values, and vice - versa. Any other NSNumber instances are converted to a JSON number the - way you would expect. - - */ - -#import "SBJsonParser.h" -#import "SBJsonWriter.h" -#import "SBJsonStreamParser.h" -#import "SBJsonStreamParserAdapter.h" -#import "SBJsonStreamWriter.h" -#import "NSObject+SBJson.h" - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonParser.h b/TwitterSearch/TwitterSearch/JSON/SBJsonParser.h deleted file mode 100755 index bf728c7..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonParser.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -/** - @brief Parse JSON Strings and NSData objects - - This uses SBJsonStreamParser internally. - - @see @ref objc2json - - */ - -@interface SBJsonParser : NSObject { - -@private - NSString *error; - NSUInteger depth, maxDepth; - -} - -/** - @brief The maximum recursing depth. - - Defaults to 32. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Description of parse error - - This method returns the trace of the last method that failed. - You need to check the return value of the call you're making to figure out - if the call actually failed, before you know call this method. - - @return A string describing the error encountered, or nil if no error occured. - - */ -@property(copy) NSString *error; - -/** - @brief Return the object represented by the given NSData object. - - The data *must* be UTF8 encoded. - - @param data An NSData containing UTF8 encoded data to parse. - @return The NSArray or NSDictionary represented by the object, or nil if an error occured. - - */ -- (id)objectWithData:(NSData*)data; - -/** - @brief Return the object represented by the given string - - This method converts its input to an NSData object containing UTF8 and calls -objectWithData: with it. - - @return The NSArray or NSDictionary represented by the object, or nil if an error occured. - */ -- (id)objectWithString:(NSString *)repr; - -/** - @brief Return the object represented by the given string - - This method calls objectWithString: internally. If an error occurs, and if @p error - is not nil, it creates an NSError object and returns this through its second argument. - - @param jsonText the json string to parse - @param error pointer to an NSError object to populate on error - - @return The NSArray or NSDictionary represented by the object, or nil if an error occured. - */ - -- (id)objectWithString:(NSString*)jsonText - error:(NSError**)error; - -@end - - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonParser.m b/TwitterSearch/TwitterSearch/JSON/SBJsonParser.m deleted file mode 100755 index 6f2e26b..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonParser.m +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright (C) 2009,2010 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonParser.h" -#import "SBJsonStreamParser.h" -#import "SBJsonStreamParserAdapter.h" -#import "SBJsonStreamParserAccumulator.h" - -@implementation SBJsonParser - -@synthesize maxDepth; -@synthesize error; - -- (id)init { - self = [super init]; - if (self) - self.maxDepth = 32u; - return self; -} - -- (void)dealloc { - [error release]; - [super dealloc]; -} - -#pragma mark Methods - -- (id)objectWithData:(NSData *)data { - - if (!data) { - self.error = @"Input was 'nil'"; - return nil; - } - - SBJsonStreamParserAccumulator *accumulator = [[[SBJsonStreamParserAccumulator alloc] init] autorelease]; - - SBJsonStreamParserAdapter *adapter = [[[SBJsonStreamParserAdapter alloc] init] autorelease]; - adapter.delegate = accumulator; - - SBJsonStreamParser *parser = [[[SBJsonStreamParser alloc] init] autorelease]; - parser.maxDepth = self.maxDepth; - parser.delegate = adapter; - - switch ([parser parse:data]) { - case SBJsonStreamParserComplete: - return accumulator.value; - break; - - case SBJsonStreamParserWaitingForData: - self.error = @"Unexpected end of input"; - break; - - case SBJsonStreamParserError: - self.error = parser.error; - break; - } - - return nil; -} - -- (id)objectWithString:(NSString *)repr { - return [self objectWithData:[repr dataUsingEncoding:NSUTF8StringEncoding]]; -} - -- (id)objectWithString:(NSString*)repr error:(NSError**)error_ { - id tmp = [self objectWithString:repr]; - if (tmp) - return tmp; - - if (error_) { - NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; - *error_ = [NSError errorWithDomain:@"org.brautaset.SBJsonParser.ErrorDomain" code:0 userInfo:ui]; - } - - return nil; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.h deleted file mode 100755 index 4d6667b..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -@class SBJsonTokeniser; -@class SBJsonStreamParser; -@class SBJsonStreamParserState; - -typedef enum { - SBJsonStreamParserComplete, - SBJsonStreamParserWaitingForData, - SBJsonStreamParserError, -} SBJsonStreamParserStatus; - - -/** - @brief Delegate for interacting directly with the stream parser - - You will most likely find it much more convenient to implement the - SBJsonStreamParserAdapterDelegate protocol instead. - */ -@protocol SBJsonStreamParserDelegate - -/// Called when object start is found -- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser; - -/// Called when object key is found -- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key; - -/// Called when object end is found -- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser; - -/// Called when array start is found -- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser; - -/// Called when array end is found -- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser; - -/// Called when a boolean value is found -- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x; - -/// Called when a null value is found -- (void)parserFoundNull:(SBJsonStreamParser*)parser; - -/// Called when a number is found -- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num; - -/// Called when a string is found -- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string; - -@end - - -/** - @brief Parse a stream of JSON data. - - Using this class directly you can reduce the apparent latency for each - download/parse cycle of documents over a slow connection. You can start - parsing *and return chunks of the parsed document* before the entire - document is downloaded. - - Using this class is also useful to parse huge documents on disk - bit by bit so you don't have to keep them all in memory. - - @see SBJsonStreamParserAdapter for more information. - - @see @ref objc2json - - */ -@interface SBJsonStreamParser : NSObject { -@private - BOOL supportMultipleDocuments; - id delegate; - SBJsonTokeniser *tokeniser; - NSMutableArray *stateStack; - __weak SBJsonStreamParserState *state; - NSUInteger maxDepth; - NSString *error; -} - -@property (nonatomic, assign) __weak SBJsonStreamParserState *state; // Private -@property (nonatomic, readonly, retain) NSMutableArray *stateStack; // Private - -/** - @brief Expect multiple documents separated by whitespace - - Normally the @p -parse: method returns SBJsonStreamParserComplete when it's found a complete JSON document. - Attempting to parse any more data at that point is considered an error. ("Garbage after JSON".) - - If you set this property to true the parser will never return SBJsonStreamParserComplete. Rather, - once an object is completed it will expect another object to immediately follow, separated - only by (optional) whitespace. - - @see The TweetStream app in the Examples - */ -@property BOOL supportMultipleDocuments; - -/** - @brief Delegate to receive messages - - The object set here receives a series of messages as the parser breaks down the JSON stream - into valid tokens. - - @note - Usually this should be an instance of SBJsonStreamParserAdapter, but you can - substitute your own implementation of the SBJsonStreamParserDelegate protocol if you need to. - */ -@property (assign) id delegate; - -/** - @brief The max parse depth - - If the input is nested deeper than this the parser will halt parsing and return an error. - - Defaults to 32. - */ -@property NSUInteger maxDepth; - -/// Holds the error after SBJsonStreamParserError was returned -@property (copy) NSString *error; - -/** - @brief Parse some JSON - - The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one. - - @param data An NSData object containing the next chunk of JSON - - @return - @li SBJsonStreamParserComplete if a full document was found - @li SBJsonStreamParserWaitingForData if a partial document was found and more data is required to complete it - @li SBJsonStreamParserError if an error occured. (See the error property for details in this case.) - - */ -- (SBJsonStreamParserStatus)parse:(NSData*)data; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.m deleted file mode 100755 index 8fb32b8..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParser.m +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamParser.h" -#import "SBJsonTokeniser.h" -#import "SBJsonStreamParserState.h" -#import - -@implementation SBJsonStreamParser - -@synthesize supportMultipleDocuments; -@synthesize error; -@synthesize delegate; -@synthesize maxDepth; -@synthesize state; -@synthesize stateStack; - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - maxDepth = 32u; - stateStack = [[NSMutableArray alloc] initWithCapacity:maxDepth]; - state = [SBJsonStreamParserStateStart sharedInstance]; - tokeniser = [[SBJsonTokeniser alloc] init]; - } - return self; -} - -- (void)dealloc { - self.error = nil; - self.state = nil; - [stateStack release]; - [tokeniser release]; - [super dealloc]; -} - -#pragma mark Methods - -- (NSString*)tokenName:(sbjson_token_t)token { - switch (token) { - case sbjson_token_array_start: - return @"start of array"; - break; - - case sbjson_token_array_end: - return @"end of array"; - break; - - case sbjson_token_number: - return @"number"; - break; - - case sbjson_token_string: - return @"string"; - break; - - case sbjson_token_true: - case sbjson_token_false: - return @"boolean"; - break; - - case sbjson_token_null: - return @"null"; - break; - - case sbjson_token_keyval_separator: - return @"key-value separator"; - break; - - case sbjson_token_separator: - return @"value separator"; - break; - - case sbjson_token_object_start: - return @"start of object"; - break; - - case sbjson_token_object_end: - return @"end of object"; - break; - - case sbjson_token_eof: - case sbjson_token_error: - break; - } - NSAssert(NO, @"Should not get here"); - return @""; -} - -- (void)maxDepthError { - self.error = [NSString stringWithFormat:@"Input depth exceeds max depth of %lu", maxDepth]; - self.state = [SBJsonStreamParserStateError sharedInstance]; -} - -- (void)handleObjectStart { - if (stateStack.count >= maxDepth) { - [self maxDepthError]; - return; - } - - [delegate parserFoundObjectStart:self]; - [stateStack addObject:state]; - self.state = [SBJsonStreamParserStateObjectStart sharedInstance]; -} - -- (void)handleArrayStart { - if (stateStack.count >= maxDepth) { - [self maxDepthError]; - return; - } - - [delegate parserFoundArrayStart:self]; - [stateStack addObject:state]; - self.state = [SBJsonStreamParserStateArrayStart sharedInstance]; -} - -- (SBJsonStreamParserStatus)parse:(NSData *)data_ { - [tokeniser appendData:data_]; - - - for (;;) { - - if ([state isKindOfClass:[SBJsonStreamParserStateError class]]) - return SBJsonStreamParserError; - - NSObject *token; - sbjson_token_t tok = [tokeniser getToken:&token]; - switch (tok) { - case sbjson_token_eof: - return [state parserShouldReturn:self]; - break; - - case sbjson_token_error: - self.state = [SBJsonStreamParserStateError sharedInstance]; - self.error = tokeniser.error; - return SBJsonStreamParserError; - break; - - default: - - if (![state parser:self shouldAcceptToken:tok]) { - NSString *tokenName = [self tokenName:tok]; - NSString *stateName = [state name]; - - self.error = [NSString stringWithFormat:@"Token '%@' not expected %@", tokenName, stateName]; - self.state = [SBJsonStreamParserStateError sharedInstance]; - return SBJsonStreamParserError; - } - - switch (tok) { - case sbjson_token_object_start: - [self handleObjectStart]; - break; - - case sbjson_token_object_end: - self.state = [stateStack lastObject]; - [stateStack removeLastObject]; - [state parser:self shouldTransitionTo:tok]; - [delegate parserFoundObjectEnd:self]; - break; - - case sbjson_token_array_start: - [self handleArrayStart]; - break; - - case sbjson_token_array_end: - self.state = [stateStack lastObject]; - [stateStack removeLastObject]; - [state parser:self shouldTransitionTo:tok]; - [delegate parserFoundArrayEnd:self]; - break; - - case sbjson_token_separator: - case sbjson_token_keyval_separator: - [state parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_true: - [delegate parser:self foundBoolean:YES]; - [state parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_false: - [delegate parser:self foundBoolean:NO]; - [state parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_null: - [delegate parserFoundNull:self]; - [state parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_number: - [delegate parser:self foundNumber:(NSNumber*)token]; - [state parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_string: - if ([state needKey]) - [delegate parser:self foundObjectKey:(NSString*)token]; - else - [delegate parser:self foundString:(NSString*)token]; - [state parser:self shouldTransitionTo:tok]; - break; - - default: - break; - } - break; - } - } - return SBJsonStreamParserComplete; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.h deleted file mode 100755 index ede76c6..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright (C) 2011 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import -#import "SBJsonStreamParserAdapter.h" - -@interface SBJsonStreamParserAccumulator : NSObject { -@private - id value; -} - -@property (readonly, copy) id value; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.m deleted file mode 100755 index 72716da..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAccumulator.m +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright (C) 2011 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamParserAccumulator.h" - -@implementation SBJsonStreamParserAccumulator - -@synthesize value; - -- (void)dealloc { - [value release]; - [super dealloc]; -} - -#pragma mark SBJsonStreamParserAdapterDelegate - -- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray *)array { - value = [array retain]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary *)dict { - value = [dict retain]; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.h deleted file mode 100755 index 4cc4b3d..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import -#import "SBJsonStreamParser.h" - -typedef enum { - SBJsonStreamParserAdapterNone, - SBJsonStreamParserAdapterArray, - SBJsonStreamParserAdapterObject, -} SBJsonStreamParserAdapterType; - -/** - @brief Delegate for getting objects & arrays from the stream parser adapter - - @see The TweetStream example project. - */ -@protocol SBJsonStreamParserAdapterDelegate - -/** - @brief Called if a JSON array is found - - This method is called if a JSON array is found. - - */ -- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray*)array; - -/** - @brief Called when a JSON object is found - - This method is called if a JSON object is found. - */ -- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary*)dict; - -@end - -/** - @brief SBJsonStreamParserDelegate protocol adapter - - Rather than implementing the SBJsonStreamParserDelegate protocol yourself you will - most likely find it much more convenient to use an instance of this class and - implement the SBJsonStreamParserAdapterDelegate protocol instead. - - Normally you would only get one call from either the -parser:foundArray: or - -parser:foundObject: method. However, if your inputs contains multiple JSON - documents and you set the parser's -supportMultipleDocuments property to YES - you will get one call for each full method. - - @code - SBJsonStreamParserAdapter *adapter = [[[SBJsonStreamParserAdapter alloc] init] autorelease]; - adapter.delegate = self; - - SBJsonStreamParser *parser = [[[SBJsonStreamParser alloc] init] autorelease]; - parser.delegate = adapter; - parser.supportMultipleDocuments = YES; - - // Note that this input contains multiple top-level JSON documents - NSData *json = [@"[]{}[]{}" dataWithEncoding:NSUTF8StringEncoding]; - [parser parse:data]; - @endcode - - In the above example @p self will have the following sequence of methods called on it: - - @li -parser:foundArray: - @li -parser:foundObject: - @li -parser:foundArray: - @li -parser:foundObject: - - Often you won't have control over the input you're parsing, so can't make use of - this feature. But, all is not lost: this class will let you get the same effect by - allowing you to skip one or more of the outer enclosing objects. Thus, the next - example results in the same sequence of -parser:foundArray: / -parser:foundObject: - being called on your delegate. - - @code - SBJsonStreamParserAdapter *adapter = [[[SBJsonStreamParserAdapter alloc] init] autorelease]; - adapter.delegate = self; - adapter.levelsToSkip = 1; - - SBJsonStreamParser *parser = [[[SBJsonStreamParser alloc] init] autorelease]; - parser.delegate = adapter; - - // Note that this input contains A SINGLE top-level document - NSData *json = [@"[[],{},[],{}]" dataWithEncoding:NSUTF8StringEncoding]; - [parser parse:data]; - @endcode - -*/ -@interface SBJsonStreamParserAdapter : NSObject { -@private - id delegate; - NSUInteger levelsToSkip, depth; - __weak NSMutableArray *array; - __weak NSMutableDictionary *dict; - NSMutableArray *keyStack; - NSMutableArray *stack; - - SBJsonStreamParserAdapterType currentType; -} - -/** - @brief How many levels to skip - - This is useful for parsing huge JSON documents, or documents coming in over a very slow link. - - If you set this to N it will skip the outer N levels and call the -parser:foundArray: - or -parser:foundObject: methods for each of the inner objects, as appropriate. - - @see The StreamParserIntegrationTest.m file for examples -*/ -@property NSUInteger levelsToSkip; - -/** - @brief Your delegate object - Set this to the object you want to receive the SBJsonStreamParserAdapterDelegate messages. - */ -@property (assign) id delegate; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.m deleted file mode 100755 index 8493e24..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserAdapter.m +++ /dev/null @@ -1,171 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamParserAdapter.h" - -@interface SBJsonStreamParserAdapter () - -- (void)pop; -- (void)parser:(SBJsonStreamParser*)parser found:(id)obj; - -@end - - - -@implementation SBJsonStreamParserAdapter - -@synthesize delegate; -@synthesize levelsToSkip; - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - keyStack = [[NSMutableArray alloc] initWithCapacity:32]; - stack = [[NSMutableArray alloc] initWithCapacity:32]; - - currentType = SBJsonStreamParserAdapterNone; - } - return self; -} - -- (void)dealloc { - [keyStack release]; - [stack release]; - [super dealloc]; -} - -#pragma mark Private methods - -- (void)pop { - [stack removeLastObject]; - array = nil; - dict = nil; - currentType = SBJsonStreamParserAdapterNone; - - id value = [stack lastObject]; - - if ([value isKindOfClass:[NSArray class]]) { - array = value; - currentType = SBJsonStreamParserAdapterArray; - } else if ([value isKindOfClass:[NSDictionary class]]) { - dict = value; - currentType = SBJsonStreamParserAdapterObject; - } -} - -- (void)parser:(SBJsonStreamParser*)parser found:(id)obj { - NSParameterAssert(obj); - - switch (currentType) { - case SBJsonStreamParserAdapterArray: - [array addObject:obj]; - break; - - case SBJsonStreamParserAdapterObject: - NSParameterAssert(keyStack.count); - [dict setObject:obj forKey:[keyStack lastObject]]; - [keyStack removeLastObject]; - break; - - case SBJsonStreamParserAdapterNone: - if ([obj isKindOfClass:[NSArray class]]) { - [delegate parser:parser foundArray:obj]; - } else { - [delegate parser:parser foundObject:obj]; - } - break; - - default: - break; - } -} - - -#pragma mark Delegate methods - -- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser { - if (++depth > levelsToSkip) { - dict = [[NSMutableDictionary new] autorelease]; - [stack addObject:dict]; - currentType = SBJsonStreamParserAdapterObject; - } -} - -- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key_ { - [keyStack addObject:key_]; -} - -- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser { - if (depth-- > levelsToSkip) { - id value = [dict retain]; - [self pop]; - [self parser:parser found:value]; - [value release]; - } -} - -- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser { - if (++depth > levelsToSkip) { - array = [[NSMutableArray new] autorelease]; - [stack addObject:array]; - currentType = SBJsonStreamParserAdapterArray; - } -} - -- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser { - if (depth-- > levelsToSkip) { - id value = [array retain]; - [self pop]; - [self parser:parser found:value]; - [value release]; - } -} - -- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x { - [self parser:parser found:[NSNumber numberWithBool:x]]; -} - -- (void)parserFoundNull:(SBJsonStreamParser*)parser { - [self parser:parser found:[NSNull null]]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num { - [self parser:parser found:num]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string { - [self parser:parser found:string]; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.h deleted file mode 100755 index accee2d..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -#import "SBJsonTokeniser.h" -#import "SBJsonStreamParser.h" - -@interface SBJsonStreamParserState : NSObject -+ (id)sharedInstance; -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token; -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser; -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok; -- (BOOL)needKey; - -- (NSString*)name; - -@end - -@interface SBJsonStreamParserStateStart : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateComplete : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateError : SBJsonStreamParserState -@end - - -@interface SBJsonStreamParserStateObjectStart : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectGotKey : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectSeparator : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectGotValue : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectNeedKey : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayStart : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayGotValue : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayNeedValue : SBJsonStreamParserState -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.m deleted file mode 100755 index a6dfdda..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamParserState.m +++ /dev/null @@ -1,347 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamParserState.h" -#import "SBJsonStreamParser.h" - -#define SINGLETON \ -+ (id)sharedInstance { \ - static id state; \ - if (!state) state = [[self alloc] init]; \ - return state; \ -} - -@implementation SBJsonStreamParserState - -+ (id)sharedInstance { return nil; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return NO; -} - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserWaitingForData; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok {} - -- (BOOL)needKey { - return NO; -} - -- (NSString*)name { - return @""; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateStart - -SINGLETON - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_array_start || token == sbjson_token_object_start; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - - SBJsonStreamParserState *state = nil; - switch (tok) { - case sbjson_token_array_start: - state = [SBJsonStreamParserStateArrayStart sharedInstance]; - break; - - case sbjson_token_object_start: - state = [SBJsonStreamParserStateObjectStart sharedInstance]; - break; - - case sbjson_token_array_end: - case sbjson_token_object_end: - if (parser.supportMultipleDocuments) - state = parser.state; - else - state = [SBJsonStreamParserStateComplete sharedInstance]; - break; - - case sbjson_token_eof: - return; - - default: - state = [SBJsonStreamParserStateError sharedInstance]; - break; - } - - - parser.state = state; -} - -- (NSString*)name { return @"before outer-most array or object"; } - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateComplete - -SINGLETON - -- (NSString*)name { return @"after outer-most array or object"; } - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserComplete; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateError - -SINGLETON - -- (NSString*)name { return @"in error"; } - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserError; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectStart - -SINGLETON - -- (NSString*)name { return @"at beginning of object"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_string: - return YES; - break; - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateObjectGotKey sharedInstance]; -} - -- (BOOL)needKey { - return YES; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectGotKey - -SINGLETON - -- (NSString*)name { return @"after object key"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_keyval_separator; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateObjectSeparator sharedInstance]; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectSeparator - -SINGLETON - -- (NSString*)name { return @"as object value"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_start: - case sbjson_token_array_start: - case sbjson_token_true: - case sbjson_token_false: - case sbjson_token_null: - case sbjson_token_number: - case sbjson_token_string: - return YES; - break; - - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateObjectGotValue sharedInstance]; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectGotValue - -SINGLETON - -- (NSString*)name { return @"after object value"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_separator: - return YES; - break; - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateObjectNeedKey sharedInstance]; -} - - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectNeedKey - -SINGLETON - -- (NSString*)name { return @"in place of object key"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return sbjson_token_string == token; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateObjectGotKey sharedInstance]; -} - -- (BOOL)needKey { - return YES; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayStart - -SINGLETON - -- (NSString*)name { return @"at array start"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_keyval_separator: - case sbjson_token_separator: - return NO; - break; - - default: - return YES; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateArrayGotValue sharedInstance]; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayGotValue - -SINGLETON - -- (NSString*)name { return @"after array value"; } - - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_array_end || token == sbjson_token_separator; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - if (tok == sbjson_token_separator) - parser.state = [SBJsonStreamParserStateArrayNeedValue sharedInstance]; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayNeedValue - -SINGLETON - -- (NSString*)name { return @"as array value"; } - - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_array_end: - case sbjson_token_keyval_separator: - case sbjson_token_object_end: - case sbjson_token_separator: - return NO; - break; - - default: - return YES; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.state = [SBJsonStreamParserStateArrayGotValue sharedInstance]; -} - -@end - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.h deleted file mode 100755 index 5c26337..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -/// Enable JSON writing for non-native objects -@interface NSObject (SBProxyForJson) - -/** - @brief Allows generation of JSON for otherwise unsupported classes. - - If you have a custom class that you want to create a JSON representation - for you can implement this method in your class. It should return a - representation of your object defined in terms of objects that can be - translated into JSON. For example, a Person object might implement it like this: - - @code - - (id)proxyForJson { - return [NSDictionary dictionaryWithObjectsAndKeys: - name, @"name", - phone, @"phone", - email, @"email", - nil]; - } - @endcode - - */ -- (id)proxyForJson; - -@end - -@class SBJsonStreamWriter; - -@protocol SBJsonStreamWriterDelegate - -- (void)writer:(SBJsonStreamWriter*)writer appendBytes:(const void *)bytes length:(NSUInteger)length; - -@end - -@class SBJsonStreamWriterState; - -/** - @brief The Stream Writer class. - - Accepts a stream of messages and writes JSON of these to its delegate object. - - This class provides a range of high-, mid- and low-level methods. You can mix - and match calls to these. For example, you may want to call -writeArrayOpen - to start an array and then repeatedly call -writeObject: with various objects - before finishing off with a -writeArrayClose call. - - @see @ref json2objc - - */ - -@interface SBJsonStreamWriter : NSObject { -@private - NSString *error; - NSMutableArray *stateStack; - __weak SBJsonStreamWriterState *state; - id delegate; - NSUInteger maxDepth; - BOOL sortKeys, humanReadable; -} - -@property (nonatomic, assign) __weak SBJsonStreamWriterState *state; // Internal -@property (nonatomic, readonly, retain) NSMutableArray *stateStack; // Internal - -/** - @brief delegate to receive JSON output - Delegate that will receive messages with output. - */ -@property (assign) id delegate; - -/** - @brief The maximum recursing depth. - - Defaults to 512. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Whether we are generating human-readable (multiline) JSON. - - Set whether or not to generate human-readable JSON. The default is NO, which produces - JSON without any whitespace between tokens. If set to YES, generates human-readable - JSON with linebreaks after each array value and dictionary key/value pair, indented two - spaces per nesting level. - */ -@property BOOL humanReadable; - -/** - @brief Whether or not to sort the dictionary keys in the output. - - If this is set to YES, the dictionary keys in the JSON output will be in sorted order. - (This is useful if you need to compare two structures, for example.) The default is NO. - */ -@property BOOL sortKeys; - -/// Contains the error description after an error has occured. -@property (copy) NSString *error; - -/** - Write an NSDictionary to the JSON stream. - @return YES if successful, or NO on failure - */ -- (BOOL)writeObject:(NSDictionary*)dict; - -/** - Write an NSArray to the JSON stream. - @return YES if successful, or NO on failure - */ -- (BOOL)writeArray:(NSArray *)array; - -/** - Start writing an Object to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeObjectOpen; - -/** - Close the current object being written - @return YES if successful, or NO on failure -*/ -- (BOOL)writeObjectClose; - -/** Start writing an Array to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeArrayOpen; - -/** Close the current Array being written - @return YES if successful, or NO on failure -*/ -- (BOOL)writeArrayClose; - -/** Write a null to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeNull; - -/** Write a boolean to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeBool:(BOOL)x; - -/** Write a Number to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeNumber:(NSNumber*)n; - -/** Write a String to the stream - @return YES if successful, or NO on failure -*/ -- (BOOL)writeString:(NSString*)s; - -@end - -@interface SBJsonStreamWriter (Private) -- (BOOL)writeValue:(id)v; -- (void)appendBytes:(const void *)bytes length:(NSUInteger)length; -@end - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.m deleted file mode 100755 index 4da28b9..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriter.m +++ /dev/null @@ -1,366 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamWriter.h" -#import "SBJsonStreamWriterState.h" - -static NSDecimalNumber *kNotANumber; -static NSCache *kStaticStringCache; - - -@implementation SBJsonStreamWriter - -@synthesize error; -@synthesize maxDepth; -@synthesize state; -@synthesize stateStack; -@synthesize humanReadable; -@synthesize sortKeys; - -+ (void)initialize { - kNotANumber = [NSDecimalNumber notANumber]; - kStaticStringCache = [[NSCache alloc] init]; -} - -#pragma mark Housekeeping - -@synthesize delegate; - -- (id)init { - self = [super init]; - if (self) { - maxDepth = 32u; - stateStack = [[NSMutableArray alloc] initWithCapacity:maxDepth]; - state = [[SBJsonStreamWriterStateStart alloc] init]; - } - return self; -} - -- (void)dealloc { - self.error = nil; - self.state = nil; - [stateStack release]; - [super dealloc]; -} - -#pragma mark Methods - -- (void)appendBytes:(const void *)bytes length:(NSUInteger)length { - [delegate writer:self appendBytes:bytes length:length]; -} - -- (BOOL)writeObject:(NSDictionary *)dict { - if (![self writeObjectOpen]) - return NO; - - NSArray *keys = [dict allKeys]; - if (sortKeys) - keys = [keys sortedArrayUsingSelector:@selector(compare:)]; - - for (id k in keys) { - if (![k isKindOfClass:[NSString class]]) { - self.error = [NSString stringWithFormat:@"JSON object key must be string: %@", k]; - return NO; - } - - if (![self writeString:k]) - return NO; - if (![self writeValue:[dict objectForKey:k]]) - return NO; - } - - return [self writeObjectClose]; -} - -- (BOOL)writeArray:(NSArray*)array { - if (![self writeArrayOpen]) - return NO; - for (id v in array) - if (![self writeValue:v]) - return NO; - return [self writeArrayClose]; -} - - -- (BOOL)writeObjectOpen { - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - [state appendSeparator:self]; - if (humanReadable && stateStack.count) [state appendWhitespace:self]; - - [stateStack addObject:state]; - self.state = [SBJsonStreamWriterStateObjectStart sharedInstance]; - - if (maxDepth && stateStack.count > maxDepth) { - self.error = @"Nested too deep"; - return NO; - } - - [delegate writer:self appendBytes:"{" length:1]; - return YES; -} - -- (BOOL)writeObjectClose { - if ([state isInvalidState:self]) return NO; - - SBJsonStreamWriterState *prev = state; - - self.state = [stateStack lastObject]; - [stateStack removeLastObject]; - - if (humanReadable) [prev appendWhitespace:self]; - [delegate writer:self appendBytes:"}" length:1]; - - [state transitionState:self]; - return YES; -} - -- (BOOL)writeArrayOpen { - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - [state appendSeparator:self]; - if (humanReadable && stateStack.count) [state appendWhitespace:self]; - - [stateStack addObject:state]; - self.state = [SBJsonStreamWriterStateArrayStart sharedInstance]; - - if (maxDepth && stateStack.count > maxDepth) { - self.error = @"Nested too deep"; - return NO; - } - - [delegate writer:self appendBytes:"[" length:1]; - return YES; -} - -- (BOOL)writeArrayClose { - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - - SBJsonStreamWriterState *prev = state; - - self.state = [stateStack lastObject]; - [stateStack removeLastObject]; - - if (humanReadable) [prev appendWhitespace:self]; - [delegate writer:self appendBytes:"]" length:1]; - - [state transitionState:self]; - return YES; -} - -- (BOOL)writeNull { - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - [state appendSeparator:self]; - if (humanReadable) [state appendWhitespace:self]; - - [delegate writer:self appendBytes:"null" length:4]; - [state transitionState:self]; - return YES; -} - -- (BOOL)writeBool:(BOOL)x { - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - [state appendSeparator:self]; - if (humanReadable) [state appendWhitespace:self]; - - if (x) - [delegate writer:self appendBytes:"true" length:4]; - else - [delegate writer:self appendBytes:"false" length:5]; - [state transitionState:self]; - return YES; -} - - -- (BOOL)writeValue:(id)o { - if ([o isKindOfClass:[NSDictionary class]]) { - return [self writeObject:o]; - - } else if ([o isKindOfClass:[NSArray class]]) { - return [self writeArray:o]; - - } else if ([o isKindOfClass:[NSString class]]) { - [self writeString:o]; - return YES; - - } else if ([o isKindOfClass:[NSNumber class]]) { - return [self writeNumber:o]; - - } else if ([o isKindOfClass:[NSNull class]]) { - return [self writeNull]; - - } else if ([o respondsToSelector:@selector(proxyForJson)]) { - return [self writeValue:[o proxyForJson]]; - - } - - self.error = [NSString stringWithFormat:@"JSON serialisation not supported for %@", [o class]]; - return NO; -} - -static const char *strForChar(int c) { - switch (c) { - case 0: return "\\u0000"; break; - case 1: return "\\u0001"; break; - case 2: return "\\u0002"; break; - case 3: return "\\u0003"; break; - case 4: return "\\u0004"; break; - case 5: return "\\u0005"; break; - case 6: return "\\u0006"; break; - case 7: return "\\u0007"; break; - case 8: return "\\b"; break; - case 9: return "\\t"; break; - case 10: return "\\n"; break; - case 11: return "\\u000b"; break; - case 12: return "\\f"; break; - case 13: return "\\r"; break; - case 14: return "\\u000e"; break; - case 15: return "\\u000f"; break; - case 16: return "\\u0010"; break; - case 17: return "\\u0011"; break; - case 18: return "\\u0012"; break; - case 19: return "\\u0013"; break; - case 20: return "\\u0014"; break; - case 21: return "\\u0015"; break; - case 22: return "\\u0016"; break; - case 23: return "\\u0017"; break; - case 24: return "\\u0018"; break; - case 25: return "\\u0019"; break; - case 26: return "\\u001a"; break; - case 27: return "\\u001b"; break; - case 28: return "\\u001c"; break; - case 29: return "\\u001d"; break; - case 30: return "\\u001e"; break; - case 31: return "\\u001f"; break; - case 34: return "\\\""; break; - case 92: return "\\\\"; break; - } - NSLog(@"FUTFUTFUT: -->'%c'<---", c); - return "FUTFUTFUT"; -} - -- (BOOL)writeString:(NSString*)string { - if ([state isInvalidState:self]) return NO; - [state appendSeparator:self]; - if (humanReadable) [state appendWhitespace:self]; - - NSMutableData *buf = [kStaticStringCache objectForKey:string]; - if (!buf) { - - NSUInteger len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - const char *utf8 = [string UTF8String]; - NSUInteger written = 0, i = 0; - - buf = [NSMutableData dataWithCapacity:len * 1.1f]; - [buf appendBytes:"\"" length:1]; - - for (i = 0; i < len; i++) { - int c = utf8[i]; - BOOL isControlChar = c >= 0 && c < 32; - if (isControlChar || c == '"' || c == '\\') { - if (i - written) - [buf appendBytes:utf8 + written length:i - written]; - written = i + 1; - - const char *t = strForChar(c); - [buf appendBytes:t length:strlen(t)]; - } - } - - if (i - written) - [buf appendBytes:utf8 + written length:i - written]; - - [buf appendBytes:"\"" length:1]; - [kStaticStringCache setObject:buf forKey:string]; - } - - [delegate writer:self appendBytes:[buf bytes] length:[buf length]]; - [state transitionState:self]; - return YES; -} - -- (BOOL)writeNumber:(NSNumber*)number { - if ((CFBooleanRef)number == kCFBooleanTrue || (CFBooleanRef)number == kCFBooleanFalse) - return [self writeBool:[number boolValue]]; - - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - [state appendSeparator:self]; - if (humanReadable) [state appendWhitespace:self]; - - if ((CFNumberRef)number == kCFNumberPositiveInfinity) { - self.error = @"+Infinity is not a valid number in JSON"; - return NO; - - } else if ((CFNumberRef)number == kCFNumberNegativeInfinity) { - self.error = @"-Infinity is not a valid number in JSON"; - return NO; - - } else if ((CFNumberRef)number == kCFNumberNaN) { - self.error = @"NaN is not a valid number in JSON"; - return NO; - - } else if (number == kNotANumber) { - self.error = @"NaN is not a valid number in JSON"; - return NO; - } - - const char *objcType = [number objCType]; - char num[128]; - size_t len; - - switch (objcType[0]) { - case 'c': case 'i': case 's': case 'l': case 'q': - len = snprintf(num, sizeof num, "%lld", [number longLongValue]); - break; - case 'C': case 'I': case 'S': case 'L': case 'Q': - len = snprintf(num, sizeof num, "%llu", [number unsignedLongLongValue]); - break; - case 'f': case 'd': default: - if ([number isKindOfClass:[NSDecimalNumber class]]) { - char const *utf8 = [[number stringValue] UTF8String]; - [delegate writer:self appendBytes:utf8 length: strlen(utf8)]; - [state transitionState:self]; - return YES; - } - len = snprintf(num, sizeof num, "%.17g", [number doubleValue]); - break; - } - [delegate writer:self appendBytes:num length: len]; - [state transitionState:self]; - return YES; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.h deleted file mode 100755 index 6a23b15..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2011 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamWriter.h" - -@interface SBJsonStreamWriterAccumulator : NSObject { -@private - NSMutableData *data; -} - -@property (readonly, copy) NSData* data; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.m deleted file mode 100755 index c82a1d2..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterAccumulator.m +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright (C) 2011 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamWriterAccumulator.h" - - -@implementation SBJsonStreamWriterAccumulator - -@synthesize data; - -- (id)init { - self = [super init]; - if (self) { - data = [[NSMutableData alloc] initWithCapacity:8096u]; - } - return self; -} - -- (void)dealloc { - [data release]; - [super dealloc]; -} - -#pragma mark SBJsonStreamWriterDelegate - -- (void)writer:(SBJsonStreamWriter *)writer appendBytes:(const void *)bytes length:(NSUInteger)length { - [data appendBytes:bytes length:length]; -} - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.h b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.h deleted file mode 100755 index 90d442a..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -@class SBJsonStreamWriter; - -@interface SBJsonStreamWriterState : NSObject -+ (id)sharedInstance; -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer; -- (void)appendSeparator:(SBJsonStreamWriter*)writer; -- (BOOL)expectingKey:(SBJsonStreamWriter*)writer; -- (void)transitionState:(SBJsonStreamWriter*)writer; -- (void)appendWhitespace:(SBJsonStreamWriter*)writer; -@end - -@interface SBJsonStreamWriterStateObjectStart : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateObjectKey : SBJsonStreamWriterStateObjectStart -@end - -@interface SBJsonStreamWriterStateObjectValue : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateArrayStart : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateArrayValue : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateStart : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateComplete : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateError : SBJsonStreamWriterState -@end - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.m b/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.m deleted file mode 100755 index 9f04cac..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonStreamWriterState.m +++ /dev/null @@ -1,139 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonStreamWriterState.h" -#import "SBJsonStreamWriter.h" - -#define SINGLETON \ -+ (id)sharedInstance { \ - static id state; \ - if (!state) state = [[self alloc] init]; \ - return state; \ -} - - -@implementation SBJsonStreamWriterState -+ (id)sharedInstance { return nil; } -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { return NO; } -- (void)appendSeparator:(SBJsonStreamWriter*)writer {} -- (BOOL)expectingKey:(SBJsonStreamWriter*)writer { return NO; } -- (void)transitionState:(SBJsonStreamWriter *)writer {} -- (void)appendWhitespace:(SBJsonStreamWriter*)writer { - [writer appendBytes:"\n" length:1]; - for (NSUInteger i = 0; i < writer.stateStack.count; i++) - [writer appendBytes:" " length:2]; -} -@end - -@implementation SBJsonStreamWriterStateObjectStart - -SINGLETON - -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.state = [SBJsonStreamWriterStateObjectValue sharedInstance]; -} -- (BOOL)expectingKey:(SBJsonStreamWriter *)writer { - writer.error = @"JSON object key must be string"; - return YES; -} -@end - -@implementation SBJsonStreamWriterStateObjectKey - -SINGLETON - -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer appendBytes:"," length:1]; -} -@end - -@implementation SBJsonStreamWriterStateObjectValue - -SINGLETON - -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer appendBytes:":" length:1]; -} -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.state = [SBJsonStreamWriterStateObjectKey sharedInstance]; -} -- (void)appendWhitespace:(SBJsonStreamWriter *)writer { - [writer appendBytes:" " length:1]; -} -@end - -@implementation SBJsonStreamWriterStateArrayStart - -SINGLETON - -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.state = [SBJsonStreamWriterStateArrayValue sharedInstance]; -} -@end - -@implementation SBJsonStreamWriterStateArrayValue - -SINGLETON - -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer appendBytes:"," length:1]; -} -@end - -@implementation SBJsonStreamWriterStateStart - -SINGLETON - - -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.state = [SBJsonStreamWriterStateComplete sharedInstance]; -} -- (void)appendSeparator:(SBJsonStreamWriter *)writer { -} -@end - -@implementation SBJsonStreamWriterStateComplete - -SINGLETON - -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { - writer.error = @"Stream is closed"; - return YES; -} -@end - -@implementation SBJsonStreamWriterStateError - -SINGLETON - -@end - diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.h b/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.h deleted file mode 100755 index bd5eb71..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -typedef enum { - sbjson_token_error = -1, - sbjson_token_eof, - - sbjson_token_array_start, - sbjson_token_array_end, - - sbjson_token_object_start, - sbjson_token_object_end, - - sbjson_token_separator, - sbjson_token_keyval_separator, - - sbjson_token_number, - sbjson_token_string, - sbjson_token_true, - sbjson_token_false, - sbjson_token_null, - -} sbjson_token_t; - -@class SBJsonUTF8Stream; - -@interface SBJsonTokeniser : NSObject { -@private - SBJsonUTF8Stream *_stream; - NSString *_error; -} - -@property (copy) NSString *error; - -- (void)appendData:(NSData*)data_; - -- (sbjson_token_t)getToken:(NSObject**)token; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.m b/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.m deleted file mode 100755 index 76eb22f..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonTokeniser.m +++ /dev/null @@ -1,461 +0,0 @@ -/* - Copyright (c) 2010-2011, Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonTokeniser.h" -#import "SBJsonUTF8Stream.h" - -#define SBStringIsIllegalSurrogateHighCharacter(x) (((x) >= 0xd800) && ((x) <= 0xdfff)) - - -@implementation SBJsonTokeniser - -@synthesize error = _error; - -- (id)init { - self = [super init]; - if (self) { - _stream = [[SBJsonUTF8Stream alloc] init]; - - } - - return self; -} - -- (void)dealloc { - [_stream release]; - [super dealloc]; -} - -- (void)appendData:(NSData *)data_ { - [_stream appendData:data_]; -} - - -- (sbjson_token_t)match:(const char *)pattern length:(NSUInteger)len retval:(sbjson_token_t)token { - if (![_stream ensureChars:len]) - return sbjson_token_eof; - - if ([_stream skipCharacters:pattern length:len]) - return token; - - char bytes[len+1]; - (void)[_stream getBytes:bytes length:len]; - - NSString *fmt = [NSString stringWithFormat:@"Expected '%%s' but found '%%.%us'", len]; - self.error = [NSString stringWithFormat:fmt, pattern, bytes]; - return sbjson_token_error; -} - -- (BOOL)decodeEscape:(unichar)ch into:(unichar*)decoded { - switch (ch) { - case '\\': - case '/': - case '"': - *decoded = ch; - break; - - case 'b': - *decoded = '\b'; - break; - - case 'n': - *decoded = '\n'; - break; - - case 'r': - *decoded = '\r'; - break; - - case 't': - *decoded = '\t'; - break; - - case 'f': - *decoded = '\f'; - break; - - default: - self.error = @"Illegal escape character"; - return NO; - break; - } - return YES; -} - -- (BOOL)decodeHexQuad:(unichar*)quad { - unichar c, tmp = 0; - - for (int i = 0; i < 4; i++) { - (void)[_stream getNextUnichar:&c]; - tmp *= 16; - switch (c) { - case '0' ... '9': - tmp += c - '0'; - break; - - case 'a' ... 'f': - tmp += 10 + c - 'a'; - break; - - case 'A' ... 'F': - tmp += 10 + c - 'A'; - break; - - default: - return NO; - } - } - *quad = tmp; - return YES; -} - -- (sbjson_token_t)getStringToken:(NSObject**)token { - NSMutableString *acc = nil; - - for (;;) { - [_stream skip]; - - unichar ch; - { - NSMutableString *string = nil; - if (![_stream getSimpleString:&string]) - return sbjson_token_eof; - - if (![_stream getUnichar:&ch]) - return sbjson_token_eof; - - if (acc) { - [acc appendString:string]; - - } else if (ch == '"') { - *token = string; - [_stream skip]; - return sbjson_token_string; - - } else { - acc = [[string mutableCopy] autorelease]; - } - } - - switch (ch) { - case 0 ... 0x1F: - self.error = [NSString stringWithFormat:@"Unescaped control character [0x%0.2X]", (int)ch]; - return sbjson_token_error; - break; - - case '"': - *token = acc; - [_stream skip]; - return sbjson_token_string; - break; - - case '\\': - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - - if (ch == 'u') { - if (![_stream ensureChars:5]) - return sbjson_token_eof; - - unichar hi; - if (![self decodeHexQuad:&hi]) { - self.error = @"Invalid hex quad"; - return sbjson_token_error; - } - - if (CFStringIsSurrogateHighCharacter(hi)) { - unichar lo; - - if (![_stream ensureChars:6]) - return sbjson_token_eof; - - (void)[_stream getNextUnichar:&ch]; - (void)[_stream getNextUnichar:&lo]; - if (ch != '\\' || lo != 'u' || ![self decodeHexQuad:&lo]) { - self.error = @"Missing low character in surrogate pair"; - return sbjson_token_error; - } - - if (!CFStringIsSurrogateLowCharacter(lo)) { - self.error = @"Invalid low character in surrogate pair"; - return sbjson_token_error; - } - - unichar pair[2] = {hi, lo}; - CFStringAppendCharacters((CFMutableStringRef)acc, pair, 2); - } else if (SBStringIsIllegalSurrogateHighCharacter(hi)) { - self.error = @"Invalid high character in surrogate pair"; - return sbjson_token_error; - } else { - CFStringAppendCharacters((CFMutableStringRef)acc, &hi, 1); - } - - - } else { - unichar decoded; - if (![self decodeEscape:ch into:&decoded]) - return sbjson_token_error; - CFStringAppendCharacters((CFMutableStringRef)acc, &decoded, 1); - } - - break; - - default: { - char bytes[1]; - [_stream getBytes:bytes length:1]; - [NSException raise:@"unexpected error" format:@"Should not get here: '%c'", *bytes]; - break; - } - } - } - return sbjson_token_eof; -} - -- (sbjson_token_t)getNumberToken:(NSObject**)token { - - NSUInteger numberStart = _stream.index; - NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet]; - - unichar ch; - if (![_stream getUnichar:&ch]) - return sbjson_token_eof; - - BOOL isNegative = NO; - if (ch == '-') { - isNegative = YES; - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - } - - if (ch == '0') { - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - - if ([digits characterIsMember:ch]) { - self.error = @"Leading zero is illegal in number"; - return sbjson_token_error; - } - } - - unsigned long long mantissa = 0; - int mantissa_length = 0; - - while ([digits characterIsMember:ch]) { - mantissa *= 10; - mantissa += (ch - '0'); - mantissa_length++; - - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - } - - short exponent = 0; - BOOL isFloat = NO; - - if (ch == '.') { - isFloat = YES; - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - - while ([digits characterIsMember:ch]) { - mantissa *= 10; - mantissa += (ch - '0'); - mantissa_length++; - exponent--; - - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - } - - if (!exponent) { - self.error = @"No digits after decimal point"; - return sbjson_token_error; - } - } - - BOOL hasExponent = NO; - if (ch == 'e' || ch == 'E') { - hasExponent = YES; - - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - - BOOL expIsNegative = NO; - if (ch == '-') { - expIsNegative = YES; - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - - } else if (ch == '+') { - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - } - - short exp = 0; - short exp_length = 0; - while ([digits characterIsMember:ch]) { - exp *= 10; - exp += (ch - '0'); - exp_length++; - - if (![_stream getNextUnichar:&ch]) - return sbjson_token_eof; - } - - if (exp_length == 0) { - self.error = @"No digits in exponent"; - return sbjson_token_error; - } - - if (expIsNegative) - exponent -= exp; - else - exponent += exp; - } - - if (!mantissa_length && isNegative) { - self.error = @"No digits after initial minus"; - return sbjson_token_error; - - } else if (mantissa_length >= 19) { - // The super slow path... for REALLY long numbers - NSUInteger index = _stream.index; - NSUInteger length = index - numberStart; - char bytes[length+1]; - - _stream.index = numberStart; - [_stream getBytes:bytes length:length]; - _stream.index = index; - - NSString *numberString = [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease]; - *token = [NSDecimalNumber decimalNumberWithString:numberString]; - - } else if (!isFloat && !hasExponent) { - if (!isNegative) - *token = [NSNumber numberWithUnsignedLongLong:mantissa]; - else - *token = [NSNumber numberWithLongLong:-mantissa]; - } else { - *token = [NSDecimalNumber decimalNumberWithMantissa:mantissa - exponent:exponent - isNegative:isNegative]; - } - - return sbjson_token_number; -} - -- (sbjson_token_t)getToken:(NSObject **)token { - - [_stream skipWhitespace]; - - unichar ch; - if (![_stream getUnichar:&ch]) - return sbjson_token_eof; - - NSUInteger oldIndexLocation = _stream.index; - sbjson_token_t tok; - - switch (ch) { - case '[': - tok = sbjson_token_array_start; - [_stream skip]; - break; - - case ']': - tok = sbjson_token_array_end; - [_stream skip]; - break; - - case '{': - tok = sbjson_token_object_start; - [_stream skip]; - break; - - case ':': - tok = sbjson_token_keyval_separator; - [_stream skip]; - break; - - case '}': - tok = sbjson_token_object_end; - [_stream skip]; - break; - - case ',': - tok = sbjson_token_separator; - [_stream skip]; - break; - - case 'n': - tok = [self match:"null" length:4 retval:sbjson_token_null]; - break; - - case 't': - tok = [self match:"true" length:4 retval:sbjson_token_true]; - break; - - case 'f': - tok = [self match:"false" length:5 retval:sbjson_token_false]; - break; - - case '"': - tok = [self getStringToken:token]; - break; - - case '0' ... '9': - case '-': - tok = [self getNumberToken:token]; - break; - - case '+': - self.error = @"Leading + is illegal in number"; - tok = sbjson_token_error; - break; - - default: - self.error = [NSString stringWithFormat:@"Illegal start of token [%c]", ch]; - tok = sbjson_token_error; - break; - } - - if (tok == sbjson_token_eof) { - // We ran out of bytes in the middle of a token. - // We don't know how to restart in mid-flight, so - // rewind to the start of the token for next attempt. - // Hopefully we'll have more data then. - _stream.index = oldIndexLocation; - } - - return tok; -} - - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.h b/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.h deleted file mode 100755 index a3e9e3d..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (c) 2011, Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - - -@interface SBJsonUTF8Stream : NSObject { -@private - const char *_bytes; - NSUInteger _length; - NSMutableData *_data; - NSUInteger _index; - NSUInteger _discarded; -} - -@property (assign) NSUInteger index; - -- (void)appendData:(NSData*)data_; - -- (void)skip; -- (void)skipWhitespace; -- (BOOL)skipCharacters:(const char *)chars length:(NSUInteger)len; - -- (BOOL)getUnichar:(unichar*)ch; -- (BOOL)getNextUnichar:(unichar*)ch; -- (BOOL)getSimpleString:(NSString**)string; - -- (BOOL)ensureChars:(NSUInteger)chars; -- (BOOL)getBytes:(char *)bytes length:(NSUInteger)length; - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.m b/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.m deleted file mode 100755 index 3cc759e..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonUTF8Stream.m +++ /dev/null @@ -1,150 +0,0 @@ -/* - Copyright (c) 2011, Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonUTF8Stream.h" - - -@implementation SBJsonUTF8Stream - -@synthesize index = _index; - -- (id)init { - self = [super init]; - if (self) { - _data = [[NSMutableData alloc] initWithCapacity:4096u]; - } - return self; -} - -- (void)dealloc { - [_data release]; - [super dealloc]; -} - -- (void)appendData:(NSData *)data_ { - - if (_index) { - // Discard data we've already parsed - [_data replaceBytesInRange:NSMakeRange(0, _index) withBytes:"" length:0]; - - // Keep track of how much we have discarded - _discarded += _index; - - // Reset index to point to current position - _index = 0; - } - - [_data appendData:data_]; - - // This is an optimisation. - _bytes = [_data bytes]; - _length = [_data length]; -} - - -- (BOOL)getUnichar:(unichar*)ch { - if (_index < _length) { - *ch = (unichar)_bytes[_index]; - return YES; - } - return NO; -} - -- (BOOL)getNextUnichar:(unichar*)ch { - if (++_index < _length) { - *ch = (unichar)_bytes[_index]; - return YES; - } - return NO; -} - -- (BOOL)getSimpleString:(NSString **)string { - NSUInteger start = _index; - while (_index < _length) { - switch (_bytes[_index]) { - case '"': - case '\\': - case 0 ... 0x1f: - *string = [[[NSString alloc] initWithBytes:(_bytes + start) length:(_index - start) encoding:NSUTF8StringEncoding] autorelease]; - return YES; - break; - default: - _index++; - break; - } - } - return NO; -} - -- (void)skip { - _index++; -} - -- (void)skipWhitespace { - while (_index < _length) { - switch (_bytes[_index]) { - case ' ': - case '\t': - case '\r': - case '\n': - _index++; - break; - default: - return; - break; - } - } -} - -- (BOOL)ensureChars:(NSUInteger)chars { - return [_data length] - _index >= chars; -} - -- (BOOL)skipCharacters:(const char *)chars length:(NSUInteger)len { - const void *bytes = [_data bytes] + _index; - if (!memcmp(bytes, chars, len)) { - _index += len; - return YES; - } - return NO; -} - -- (BOOL)getBytes:(char *)bytes length:(NSUInteger)length { - if (![self ensureChars:length]) - return NO; - - memcpy(bytes, _bytes + _index, length); - bytes[length] = 0x0; // terminating NUL byte - return YES; -} - - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.h b/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.h deleted file mode 100755 index 8c167e0..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -/** - @brief The JSON writer class. - - This uses SBJsonStreamWriter internally. - - @see @ref json2objc - */ - -@interface SBJsonWriter : NSObject { -@private - NSString *error; - NSUInteger maxDepth; - BOOL sortKeys, humanReadable; -} - -/** - @brief The maximum recursing depth. - - Defaults to 32. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Return an error trace, or nil if there was no errors. - - Note that this method returns the trace of the last method that failed. - You need to check the return value of the call you're making to figure out - if the call actually failed, before you know call this method. - */ -@property (readonly, copy) NSString *error; - -/** - @brief Whether we are generating human-readable (multiline) JSON. - - Set whether or not to generate human-readable JSON. The default is NO, which produces - JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable - JSON with linebreaks after each array value and dictionary key/value pair, indented two - spaces per nesting level. - */ -@property BOOL humanReadable; - -/** - @brief Whether or not to sort the dictionary keys in the output. - - If this is set to YES, the dictionary keys in the JSON output will be in sorted order. - (This is useful if you need to compare two structures, for example.) The default is NO. - */ -@property BOOL sortKeys; - -/** - @brief Return JSON representation for the given object. - - Returns a string containing JSON representation of the passed in value, or nil on error. - If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. - - @param value any instance that can be represented as JSON text. - */ -- (NSString*)stringWithObject:(id)value; - -/** - @brief Return JSON representation for the given object. - - Returns an NSData object containing JSON represented as UTF8 text, or nil on error. - - @param value any instance that can be represented as JSON text. - */ -- (NSData*)dataWithObject:(id)value; - -/** - @brief Return JSON representation (or fragment) for the given object. - - Returns a string containing JSON representation of the passed in value, or nil on error. - If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. - - @param value any instance that can be represented as a JSON fragment - @param error pointer to object to be populated with NSError on failure - - */- (NSString*)stringWithObject:(id)value - error:(NSError**)error; - - -@end diff --git a/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.m b/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.m deleted file mode 100755 index 15d1414..0000000 --- a/TwitterSearch/TwitterSearch/JSON/SBJsonWriter.m +++ /dev/null @@ -1,113 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "SBJsonWriter.h" -#import "SBJsonStreamWriter.h" -#import "SBJsonStreamWriterAccumulator.h" - - -@interface SBJsonWriter () -@property (copy) NSString *error; -@end - -@implementation SBJsonWriter - -@synthesize sortKeys; -@synthesize humanReadable; - -@synthesize error; -@synthesize maxDepth; - -- (id)init { - self = [super init]; - if (self) { - self.maxDepth = 32u; - } - return self; -} - -- (void)dealloc { - [error release]; - [super dealloc]; -} - -- (NSString*)stringWithObject:(id)value { - NSData *data = [self dataWithObject:value]; - if (data) - return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; - return nil; -} - -- (NSString*)stringWithObject:(id)value error:(NSError**)error_ { - NSString *tmp = [self stringWithObject:value]; - if (tmp) - return tmp; - - if (error_) { - NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; - *error_ = [NSError errorWithDomain:@"org.brautaset.SBJsonWriter.ErrorDomain" code:0 userInfo:ui]; - } - - return nil; -} - -- (NSData*)dataWithObject:(id)object { - self.error = nil; - - SBJsonStreamWriterAccumulator *accumulator = [[[SBJsonStreamWriterAccumulator alloc] init] autorelease]; - - SBJsonStreamWriter *streamWriter = [[[SBJsonStreamWriter alloc] init] autorelease]; - streamWriter.sortKeys = self.sortKeys; - streamWriter.maxDepth = self.maxDepth; - streamWriter.humanReadable = self.humanReadable; - streamWriter.delegate = accumulator; - - BOOL ok = NO; - if ([object isKindOfClass:[NSDictionary class]]) - ok = [streamWriter writeObject:object]; - - else if ([object isKindOfClass:[NSArray class]]) - ok = [streamWriter writeArray:object]; - - else if ([object respondsToSelector:@selector(proxyForJson)]) - return [self dataWithObject:[object proxyForJson]]; - else { - self.error = @"Not valid type for JSON"; - return nil; - } - - if (ok) - return accumulator.data; - - self.error = streamWriter.error; - return nil; -} - - -@end diff --git a/TwitterSearch/TwitterSearch/SearchViewController.m b/TwitterSearch/TwitterSearch/SearchViewController.m deleted file mode 100644 index 260ab5c..0000000 --- a/TwitterSearch/TwitterSearch/SearchViewController.m +++ /dev/null @@ -1,220 +0,0 @@ -// -// SearchViewController.m -// Created by Keith Harrison on 06-June-2011 http://useyourloaf.com -// Copyright (c) 2011 Keith Harrison. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// Neither the name of Keith Harrison nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ''AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import "SearchViewController.h" -#import "SBJSON.h" - -@interface SearchViewController () -- (void)loadQuery; -- (void)handleError:(NSError *)error; -- (void)cancelConnection; -@end - -@implementation SearchViewController - -@synthesize query=_query; -@synthesize connection=_connection; -@synthesize buffer=_buffer; -@synthesize results=_results; - -#pragma mark - -#pragma mark === View Setup === -#pragma mark - - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.title = self.query; - [self loadQuery]; -} - -- (void)viewDidUnload -{ - [super viewDidUnload]; - [self cancelConnection]; -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [self cancelConnection]; -} - -- (void)dealloc -{ - [self cancelConnection]; - [_connection release]; - [_buffer release]; - [_results release]; - [_query release]; - [super dealloc]; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return YES; -} - -#pragma mark - -#pragma mark === UITableViewDataSource Delegates === -#pragma mark - - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView -{ - return 1; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - NSUInteger count = [self.results count]; - return count > 0 ? count : 1; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString *ResultCellIdentifier = @"ResultCell"; - static NSString *LoadCellIdentifier = @"LoadingCell"; - - NSUInteger count = [self.results count]; - if ((count == 0) && (indexPath.row == 0)) { - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LoadCellIdentifier]; - if (cell == nil) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:LoadCellIdentifier] autorelease]; - cell.textLabel.textAlignment = UITextAlignmentCenter; - } - - if (self.connection) { - cell.textLabel.text = @"Loading..."; - } else { - cell.textLabel.text = @"Not available"; - } - return cell; - } - - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ResultCellIdentifier]; - if (cell == nil) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault - reuseIdentifier:ResultCellIdentifier] autorelease]; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - cell.textLabel.numberOfLines = 0; - cell.textLabel.font = [UIFont systemFontOfSize:14.0]; - } - - NSDictionary *tweet = [self.results objectAtIndex:indexPath.row]; - cell.textLabel.text = [NSString stringWithFormat:@"%@: %@", [tweet objectForKey:@"from_user"], - [tweet objectForKey:@"text"]]; - return cell; -} - -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { - - if (indexPath.row & 1) { - cell.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0]; - } else { - cell.backgroundColor = [UIColor whiteColor]; - } -} - -#pragma mark - -#pragma mark === Private methods === -#pragma mark - - -#define RESULTS_PERPAGE 100 - -- (void)loadQuery { - - NSString *path = [NSString stringWithFormat:@"http://search.twitter.com/search.json?rpp=%d&q=%@", - RESULTS_PERPAGE,self.query]; - path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:path]]; - self.connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; - [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; -} - -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - - self.buffer = [NSMutableData data]; -} - -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - - [self.buffer appendData:data]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; - self.connection = nil; - - NSString *jsonString = [[NSString alloc] initWithData:self.buffer encoding:NSUTF8StringEncoding]; - NSDictionary *jsonResults = [jsonString JSONValue]; - self.results = [jsonResults objectForKey:@"results"]; - - [jsonString release]; - self.buffer = nil; - [self.tableView reloadData]; - [self.tableView flashScrollIndicators]; -} - -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; - self.connection = nil; - self.buffer = nil; - - [self handleError:error]; - [self.tableView reloadData]; -} - -- (void)handleError:(NSError *)error -{ - NSString *errorMessage = [error localizedDescription]; - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Connection Error" - message:errorMessage - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alertView show]; - [alertView release]; -} - -- (void)cancelConnection -{ - if (self.connection != nil) - { - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; - [self.connection cancel]; - self.connection = nil; - self.buffer = nil; - } -} - -@end - diff --git a/TwitterSearch/TwitterSearch/SearchViewController.xib b/TwitterSearch/TwitterSearch/SearchViewController.xib deleted file mode 100644 index d0ca2f6..0000000 --- a/TwitterSearch/TwitterSearch/SearchViewController.xib +++ /dev/null @@ -1,167 +0,0 @@ - - - - 1056 - 10J869 - 1306 - 1038.35 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 301 - - - YES - IBProxyObject - IBUITableView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - {320, 247} - - - - 3 - MQA - - YES - IBCocoaTouchFramework - YES - 1 - 0 - YES - 84 - 22 - 22 - - - - - YES - - - dataSource - - - - 5 - - - - delegate - - - - 6 - - - - view - - - - 7 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 4.IBPluginDependency - - - YES - SearchViewController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 7 - - - - YES - - SearchViewController - UITableViewController - - IBProjectSource - ./Classes/SearchViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 301 - - diff --git a/TwitterSearch/TwitterSearch/TwitterSearch-Prefix.pch b/TwitterSearch/TwitterSearch/TwitterSearch-Prefix.pch deleted file mode 100644 index 3347aac..0000000 --- a/TwitterSearch/TwitterSearch/TwitterSearch-Prefix.pch +++ /dev/null @@ -1,14 +0,0 @@ -// -// Prefix header for all source files of the 'TwitterSearch' target in the 'TwitterSearch' project -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iPhone SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/TwitterSearch/TwitterSearch/en.lproj/MainWindow.xib b/TwitterSearch/TwitterSearch/en.lproj/MainWindow.xib deleted file mode 100644 index 282a89f..0000000 --- a/TwitterSearch/TwitterSearch/en.lproj/MainWindow.xib +++ /dev/null @@ -1,313 +0,0 @@ - - - - 1024 - 10J869 - 1306 - 1038.35 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 301 - - - YES - IBProxyObject - IBUINavigationController - IBUIViewController - IBUICustomObject - IBUIWindow - IBUINavigationBar - IBUINavigationItem - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - IBCocoaTouchFramework - - - - 1316 - - {320, 480} - - - - - 1 - MSAxIDEAA - - NO - NO - - IBCocoaTouchFramework - YES - - - - - 1 - 1 - - IBCocoaTouchFramework - NO - - - 256 - {0, 0} - NO - YES - YES - IBCocoaTouchFramework - - - YES - - - - Search - IBCocoaTouchFramework - - - RootViewController - - - 1 - 1 - - IBCocoaTouchFramework - NO - - - - - - - YES - - - delegate - - - - 4 - - - - window - - - - 5 - - - - navigationController - - - - 15 - - - - - YES - - 0 - - - - - - 2 - - - YES - - - - - -1 - - - File's Owner - - - 3 - - - - - -2 - - - - - 9 - - - YES - - - - - - - 11 - - - - - 13 - - - YES - - - - - - 14 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 11.IBPluginDependency - 13.CustomClassName - 13.IBPluginDependency - 2.IBAttributePlaceholdersKey - 2.IBEditorWindowLastContentRect - 2.IBPluginDependency - 3.CustomClassName - 3.IBPluginDependency - 9.IBEditorWindowLastContentRect - 9.IBPluginDependency - - - YES - UIApplication - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - RootViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - YES - - - - {{673, 376}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - TwitterSearchAppDelegate - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - {{186, 376}, {320, 480}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 16 - - - - YES - - RootViewController - UIViewController - - IBProjectSource - ./Classes/RootViewController.h - - - - TwitterSearchAppDelegate - NSObject - - YES - - YES - navigationController - window - - - YES - UINavigationController - UIWindow - - - - YES - - YES - navigationController - window - - - YES - - navigationController - UINavigationController - - - window - UIWindow - - - - - IBProjectSource - ./Classes/TwitterSearchAppDelegate.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 301 - - diff --git a/TwitterSearch/TwitterSearch/en.lproj/RootViewController.xib b/TwitterSearch/TwitterSearch/en.lproj/RootViewController.xib deleted file mode 100644 index 35fa196..0000000 --- a/TwitterSearch/TwitterSearch/en.lproj/RootViewController.xib +++ /dev/null @@ -1,197 +0,0 @@ - - - - 784 - 10J869 - 1306 - 1038.35 - 461.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 301 - - - YES - IBProxyObject - IBUIView - IBUITextField - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - YES - - - 290 - {{20, 37}, {280, 31}} - - - NO - YES - IBCocoaTouchFramework - 0 - - 3 - Enter search terms - - 3 - MAA - - 2 - - - YES - 17 - - IBCocoaTouchFramework - - - - {320, 460} - - - - 3 - MQA - - - IBCocoaTouchFramework - - - - - YES - - - delegate - - - - 9 - - - - view - - - - 10 - - - - - YES - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - YES - - - - - - 7 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 6.IBPluginDependency - 7.IBPluginDependency - - - YES - RootViewController - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 10 - - - - YES - - RootViewController - UIViewController - - IBProjectSource - ./Classes/RootViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 301 - - diff --git a/TwitterSearch/TwitterSearch/main.m b/TwitterSearch/TwitterSearch/main.m deleted file mode 100644 index f76a0d1..0000000 --- a/TwitterSearch/TwitterSearch/main.m +++ /dev/null @@ -1,17 +0,0 @@ -// -// main.m -// TwitterSearch -// -// Created by Keith Harrison on 06/06/2011. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - -#import - -int main(int argc, char *argv[]) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - int retVal = UIApplicationMain(argc, argv, nil, nil); - [pool release]; - return retVal; -} diff --git a/Validate/README.md b/Validate/README.md new file mode 100644 index 0000000..4329027 --- /dev/null +++ b/Validate/README.md @@ -0,0 +1,11 @@ +# Getting Started with Combine + +A gentle introduction to using Combine to validate user input. + +See the following blog post for more details: + ++ [Getting Started with Combine](https://useyourloaf.com/blog/getting-started-with-combine/) + +For details on using Xcode previews with UIKit view controllers see: + ++ [Xcode Previews for View Controllers](https:/useyourloaf.com/blog/xcode-previews-for-view-controllers/) diff --git a/Validate/Validate.xcodeproj/project.pbxproj b/Validate/Validate.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f2273c2 --- /dev/null +++ b/Validate/Validate.xcodeproj/project.pbxproj @@ -0,0 +1,357 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 532A2F1D2425823D00A0005F /* String+Blank.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532A2F1C2425823D00A0005F /* String+Blank.swift */; }; + 5371387A243202D6006CB01D /* TermsViewControllerPreviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53713879243202D6006CB01D /* TermsViewControllerPreviews.swift */; }; + 5385DF762427C259001E63E0 /* AdaptiveScroll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5385DF752427C259001E63E0 /* AdaptiveScroll.swift */; }; + 539CD53024250D75000E2699 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 539CD52F24250D75000E2699 /* AppDelegate.swift */; }; + 539CD53224250D75000E2699 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 539CD53124250D75000E2699 /* SceneDelegate.swift */; }; + 539CD53724250D75000E2699 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 539CD53524250D75000E2699 /* Main.storyboard */; }; + 539CD53924250D76000E2699 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 539CD53824250D76000E2699 /* Assets.xcassets */; }; + 539CD53C24250D76000E2699 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 539CD53A24250D76000E2699 /* LaunchScreen.storyboard */; }; + 539CD5442425109F000E2699 /* TermsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 539CD5432425109F000E2699 /* TermsViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 532A2F1C2425823D00A0005F /* String+Blank.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Blank.swift"; sourceTree = ""; }; + 53713879243202D6006CB01D /* TermsViewControllerPreviews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsViewControllerPreviews.swift; sourceTree = ""; }; + 5385DF752427C259001E63E0 /* AdaptiveScroll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveScroll.swift; sourceTree = ""; }; + 539CD52C24250D75000E2699 /* Validate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Validate.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 539CD52F24250D75000E2699 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 539CD53124250D75000E2699 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 539CD53624250D75000E2699 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 539CD53824250D76000E2699 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 539CD53B24250D76000E2699 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 539CD53D24250D76000E2699 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 539CD5432425109F000E2699 /* TermsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsViewController.swift; sourceTree = ""; }; + 53D7D6D52429223700ACD670 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 539CD52924250D75000E2699 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 539CD52324250D75000E2699 = { + isa = PBXGroup; + children = ( + 53D7D6D52429223700ACD670 /* README.md */, + 539CD52E24250D75000E2699 /* Validate */, + 539CD52D24250D75000E2699 /* Products */, + ); + sourceTree = ""; + }; + 539CD52D24250D75000E2699 /* Products */ = { + isa = PBXGroup; + children = ( + 539CD52C24250D75000E2699 /* Validate.app */, + ); + name = Products; + sourceTree = ""; + }; + 539CD52E24250D75000E2699 /* Validate */ = { + isa = PBXGroup; + children = ( + 539CD5432425109F000E2699 /* TermsViewController.swift */, + 53713879243202D6006CB01D /* TermsViewControllerPreviews.swift */, + 5385DF752427C259001E63E0 /* AdaptiveScroll.swift */, + 532A2F1C2425823D00A0005F /* String+Blank.swift */, + 539CD52F24250D75000E2699 /* AppDelegate.swift */, + 539CD53124250D75000E2699 /* SceneDelegate.swift */, + 539CD53524250D75000E2699 /* Main.storyboard */, + 539CD53824250D76000E2699 /* Assets.xcassets */, + 539CD53A24250D76000E2699 /* LaunchScreen.storyboard */, + 539CD53D24250D76000E2699 /* Info.plist */, + ); + path = Validate; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 539CD52B24250D75000E2699 /* Validate */ = { + isa = PBXNativeTarget; + buildConfigurationList = 539CD54024250D76000E2699 /* Build configuration list for PBXNativeTarget "Validate" */; + buildPhases = ( + 539CD52824250D75000E2699 /* Sources */, + 539CD52924250D75000E2699 /* Frameworks */, + 539CD52A24250D75000E2699 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Validate; + productName = Validate; + productReference = 539CD52C24250D75000E2699 /* Validate.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 539CD52424250D75000E2699 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1140; + LastUpgradeCheck = 1140; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 539CD52B24250D75000E2699 = { + CreatedOnToolsVersion = 11.4; + }; + }; + }; + buildConfigurationList = 539CD52724250D75000E2699 /* Build configuration list for PBXProject "Validate" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 539CD52324250D75000E2699; + productRefGroup = 539CD52D24250D75000E2699 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 539CD52B24250D75000E2699 /* Validate */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 539CD52A24250D75000E2699 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 539CD53C24250D76000E2699 /* LaunchScreen.storyboard in Resources */, + 539CD53924250D76000E2699 /* Assets.xcassets in Resources */, + 539CD53724250D75000E2699 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 539CD52824250D75000E2699 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 539CD53024250D75000E2699 /* AppDelegate.swift in Sources */, + 5371387A243202D6006CB01D /* TermsViewControllerPreviews.swift in Sources */, + 5385DF762427C259001E63E0 /* AdaptiveScroll.swift in Sources */, + 539CD5442425109F000E2699 /* TermsViewController.swift in Sources */, + 539CD53224250D75000E2699 /* SceneDelegate.swift in Sources */, + 532A2F1D2425823D00A0005F /* String+Blank.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 539CD53524250D75000E2699 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 539CD53624250D75000E2699 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 539CD53A24250D76000E2699 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 539CD53B24250D76000E2699 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 539CD53E24250D76000E2699 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 539CD53F24250D76000E2699 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 539CD54124250D76000E2699 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Validate/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Validate; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 539CD54224250D76000E2699 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Validate/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Validate; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 539CD52724250D75000E2699 /* Build configuration list for PBXProject "Validate" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 539CD53E24250D76000E2699 /* Debug */, + 539CD53F24250D76000E2699 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 539CD54024250D76000E2699 /* Build configuration list for PBXNativeTarget "Validate" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 539CD54124250D76000E2699 /* Debug */, + 539CD54224250D76000E2699 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 539CD52424250D75000E2699 /* Project object */; +} diff --git a/Validate/Validate/AdaptiveScroll.swift b/Validate/Validate/AdaptiveScroll.swift new file mode 100644 index 0000000..5f43115 --- /dev/null +++ b/Validate/Validate/AdaptiveScroll.swift @@ -0,0 +1,67 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class AdaptiveScrollView: UIScrollView { + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + private func setup() { + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(_:)), name: UIResponder.keyboardDidShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) + } + + @objc private func keyboardDidShow(_ notification: Notification) { + guard let userInfo = notification.userInfo, + let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { + return + } + + let keyboardSize = keyboardFrame.cgRectValue.size + let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0) + adjustContentInsets(contentInsets) + } + + @objc private func keyboardWillHide(_ notification: Notification) { + adjustContentInsets(.zero) + } + + private func adjustContentInsets(_ contentInsets: UIEdgeInsets) { + contentInset = contentInsets + scrollIndicatorInsets = contentInsets + } +} diff --git a/Validate/Validate/AppDelegate.swift b/Validate/Validate/AppDelegate.swift new file mode 100644 index 0000000..2d32c08 --- /dev/null +++ b/Validate/Validate/AppDelegate.swift @@ -0,0 +1,34 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { +} diff --git a/Validate/Validate/Assets.xcassets/AppIcon.appiconset/Contents.json b/Validate/Validate/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/Validate/Validate/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Validate/Validate/Assets.xcassets/Contents.json b/Validate/Validate/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Validate/Validate/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Validate/Validate/Assets.xcassets/disabledButton.imageset/Contents.json b/Validate/Validate/Assets.xcassets/disabledButton.imageset/Contents.json new file mode 100644 index 0000000..bf86622 --- /dev/null +++ b/Validate/Validate/Assets.xcassets/disabledButton.imageset/Contents.json @@ -0,0 +1,29 @@ +{ + "images" : [ + { + "filename" : "grey.pdf", + "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "bottom" : 10, + "left" : 10, + "right" : 10, + "top" : 10 + }, + "center" : { + "height" : 1, + "mode" : "tile", + "width" : 1 + }, + "mode" : "9-part" + } + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Validate/Validate/Assets.xcassets/disabledButton.imageset/grey.pdf b/Validate/Validate/Assets.xcassets/disabledButton.imageset/grey.pdf new file mode 100644 index 0000000..759973b Binary files /dev/null and b/Validate/Validate/Assets.xcassets/disabledButton.imageset/grey.pdf differ diff --git a/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/Contents.json b/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/Contents.json new file mode 100644 index 0000000..a9f61c7 --- /dev/null +++ b/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/Contents.json @@ -0,0 +1,29 @@ +{ + "images" : [ + { + "filename" : "greensel.pdf", + "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "bottom" : 10, + "left" : 10, + "right" : 10, + "top" : 10 + }, + "center" : { + "height" : 1, + "mode" : "tile", + "width" : 1 + }, + "mode" : "9-part" + } + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/greensel.pdf b/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/greensel.pdf new file mode 100644 index 0000000..7b4ae44 Binary files /dev/null and b/Validate/Validate/Assets.xcassets/selectedSubmit.imageset/greensel.pdf differ diff --git a/Validate/Validate/Assets.xcassets/submitButton.imageset/Contents.json b/Validate/Validate/Assets.xcassets/submitButton.imageset/Contents.json new file mode 100644 index 0000000..fec438a --- /dev/null +++ b/Validate/Validate/Assets.xcassets/submitButton.imageset/Contents.json @@ -0,0 +1,29 @@ +{ + "images" : [ + { + "filename" : "green.pdf", + "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "bottom" : 12, + "left" : 10, + "right" : 10, + "top" : 12 + }, + "center" : { + "height" : 1, + "mode" : "tile", + "width" : 1 + }, + "mode" : "9-part" + } + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Validate/Validate/Assets.xcassets/submitButton.imageset/green.pdf b/Validate/Validate/Assets.xcassets/submitButton.imageset/green.pdf new file mode 100644 index 0000000..b3fa12c Binary files /dev/null and b/Validate/Validate/Assets.xcassets/submitButton.imageset/green.pdf differ diff --git a/Validate/Validate/Base.lproj/LaunchScreen.storyboard b/Validate/Validate/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/Validate/Validate/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Validate/Validate/Base.lproj/Main.storyboard b/Validate/Validate/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9b9f35e --- /dev/null +++ b/Validate/Validate/Base.lproj/Main.storyboard @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + You must accept these terms and conditions before continuing: + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus nec posuere nulla, sit amet fermentum tellus. Pellentesque bibendum eros sed mi ultricies hendrerit quis id mi. Curabitur quis sodales eros. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Validate/Validate/Info.plist b/Validate/Validate/Info.plist new file mode 100644 index 0000000..2a3483c --- /dev/null +++ b/Validate/Validate/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Validate/Validate/SceneDelegate.swift b/Validate/Validate/SceneDelegate.swift new file mode 100644 index 0000000..d6c5aaa --- /dev/null +++ b/Validate/Validate/SceneDelegate.swift @@ -0,0 +1,34 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + var window: UIWindow? +} diff --git a/Validate/Validate/String+Blank.swift b/Validate/Validate/String+Blank.swift new file mode 100644 index 0000000..22fb8f3 --- /dev/null +++ b/Validate/Validate/String+Blank.swift @@ -0,0 +1,46 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Foundation + +extension String { + /// A Boolean value indicating whether a String is blank. + /// The string is blank if it is empty or only contains whitespace. + var isBlank: Bool { + return allSatisfy { $0.isWhitespace } + } +} + +extension Optional where Wrapped == String { + /// A Boolean value indicating whether an Optional String is blank. + /// The optional string is blank if it is nil, empty or only contains whitespace. + var isBlank: Bool { + return self?.isBlank ?? true + } +} diff --git a/Validate/Validate/TermsViewController.swift b/Validate/Validate/TermsViewController.swift new file mode 100644 index 0000000..3ca2409 --- /dev/null +++ b/Validate/Validate/TermsViewController.swift @@ -0,0 +1,115 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import Combine +import UIKit + +final class TermsViewController: UIViewController { + @IBOutlet private var termsSwitch: UISwitch! + @IBOutlet private var privacySwitch: UISwitch! + @IBOutlet private var nameField: UITextField! + @IBOutlet private var submitButton: UIButton! + + @Published private var acceptedTerms: Bool = false + @Published private var acceptedPrivacy: Bool = false + @Published private var name: String = "" + + private var stream: AnyCancellable? + + override func viewDidLoad() { + super.viewDidLoad() + stream = validToSubmit + .receive(on: RunLoop.main) + .assign(to: \.isEnabled, on: submitButton) + } + + @IBAction private func acceptTerms(_ sender: UISwitch) { + acceptedTerms = sender.isOn + } + + @IBAction private func acceptPrivacy(_ sender: UISwitch) { + acceptedPrivacy = sender.isOn + } + + @IBAction private func nameChanged(_ sender: UITextField) { + name = sender.text ?? "" + } + + @IBAction private func submitAction(_ sender: UIButton) { + print("Submit... \(name)") + print(view.value(forKey: "_autolayoutTrace")!) + } + + private var validToSubmit: AnyPublisher { + return Publishers.CombineLatest3($acceptedTerms, $acceptedPrivacy, $name) + .map { terms, privacy, name in + terms && privacy && !name.isBlank + }.eraseToAnyPublisher() + } + + // A longer approach just for fun: + // + // private var validName: AnyPublisher { + // return $name.map { name in + // guard !name.isBlank && name.count > 2 else { return nil } + // return name + // }.eraseToAnyPublisher() + // } + // + // private var acceptedAll: AnyPublisher { + // return Publishers.CombineLatest($acceptedTerms, $acceptedPrivacy) + // .map { terms, privacy in + // terms && privacy + // }.eraseToAnyPublisher() + // } + // + // private var validToSubmit: AnyPublisher { + // return Publishers.CombineLatest(acceptedAll, validName) + // .map { terms, name in + // terms && name != nil + // }.eraseToAnyPublisher() + // } +} + +#if DEBUG +import SwiftUI + +extension TermsViewController: UIViewControllerRepresentable { + func makeUIViewController(context: Context) -> TermsViewController { + let storyboard = UIStoryboard(name: "Main", bundle: nil) + guard let viewController = storyboard.instantiateViewController(identifier: "TermsViewController") as? TermsViewController else { + fatalError("Cannot load from storyboard") + } + return viewController + } + + func updateUIViewController(_ uiViewController: TermsViewController, context: Context) { + } +} +#endif diff --git a/Validate/Validate/TermsViewControllerPreviews.swift b/Validate/Validate/TermsViewControllerPreviews.swift new file mode 100644 index 0000000..d32af21 --- /dev/null +++ b/Validate/Validate/TermsViewControllerPreviews.swift @@ -0,0 +1,71 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright © 2020 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#if DEBUG +import SwiftUI + +let devices = [ + "iPhone SE", + "iPhone 11", + "iPad Pro (11-inch) (2nd generation)" +] + +let sizeCategories: [ContentSizeCategory] = [ + .extraSmall, + .extraExtraExtraLarge, + .accessibilityExtraExtraExtraLarge +] + +struct TermsViewControllerPreviews: PreviewProvider { + static var previews: some View { + Group { + TermsViewController() + .previewDisplayName("Default") + + ForEach(devices, id: \.self) { name in + TermsViewController() + .previewDevice(PreviewDevice(rawValue: name)) + .previewDisplayName(name) + } + + ForEach(ColorScheme.allCases, id: \.self) { scheme in + TermsViewController() + .environment(\.colorScheme, scheme) + .previewDisplayName("\(scheme)") + } + + ForEach(sizeCategories, id: \.self) { size in + TermsViewController() + .environment(\.sizeCategory, size) + .previewDisplayName("\(size)") + } + } + } +} +#endif diff --git a/Vector/README.md b/Vector/README.md new file mode 100644 index 0000000..fcf48ea --- /dev/null +++ b/Vector/README.md @@ -0,0 +1,12 @@ +# Vector + +## Scaled Vector Images + +Examples of using the new *Preserve Vector Data* asset catalog feature, introduced with Xcode 9, to create smooth scaling images. This also makes it easy to support two new accessibility features in iOS 11: + ++ Adjusing Image Sizes For Accessibility ++ Large Content Size Images For Bar Items + +For full details see the blog post: + ++ [Xcode 9 Vector Images](https://useyourloaf.com/blog/xcode-9-vector-images/) diff --git a/Vector/Vector.xcodeproj/project.pbxproj b/Vector/Vector.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2589db3 --- /dev/null +++ b/Vector/Vector.xcodeproj/project.pbxproj @@ -0,0 +1,330 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 53D182791F669CBB001F1840 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D182781F669CBB001F1840 /* AppDelegate.swift */; }; + 53D182801F669CBB001F1840 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D1827E1F669CBB001F1840 /* Main.storyboard */; }; + 53D182821F669CBB001F1840 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53D182811F669CBB001F1840 /* Assets.xcassets */; }; + 53D182851F669CBB001F1840 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53D182831F669CBB001F1840 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 53D182751F669CBB001F1840 /* Vector.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Vector.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 53D182781F669CBB001F1840 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 53D1827F1F669CBB001F1840 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53D182811F669CBB001F1840 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 53D182841F669CBB001F1840 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 53D182861F669CBB001F1840 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 53D1828C1F66A024001F1840 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 53D182721F669CBB001F1840 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 53D1826C1F669CBB001F1840 = { + isa = PBXGroup; + children = ( + 53D1828C1F66A024001F1840 /* README.md */, + 53D182771F669CBB001F1840 /* Vector */, + 53D182761F669CBB001F1840 /* Products */, + ); + sourceTree = ""; + }; + 53D182761F669CBB001F1840 /* Products */ = { + isa = PBXGroup; + children = ( + 53D182751F669CBB001F1840 /* Vector.app */, + ); + name = Products; + sourceTree = ""; + }; + 53D182771F669CBB001F1840 /* Vector */ = { + isa = PBXGroup; + children = ( + 53D182781F669CBB001F1840 /* AppDelegate.swift */, + 53D1827E1F669CBB001F1840 /* Main.storyboard */, + 53D182811F669CBB001F1840 /* Assets.xcassets */, + 53D182831F669CBB001F1840 /* LaunchScreen.storyboard */, + 53D182861F669CBB001F1840 /* Info.plist */, + ); + path = Vector; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 53D182741F669CBB001F1840 /* Vector */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53D182891F669CBB001F1840 /* Build configuration list for PBXNativeTarget "Vector" */; + buildPhases = ( + 53D182711F669CBB001F1840 /* Sources */, + 53D182721F669CBB001F1840 /* Frameworks */, + 53D182731F669CBB001F1840 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Vector; + productName = Vector; + productReference = 53D182751F669CBB001F1840 /* Vector.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 53D1826D1F669CBB001F1840 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "Keith Harrison"; + TargetAttributes = { + 53D182741F669CBB001F1840 = { + CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 1120; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 53D182701F669CBB001F1840 /* Build configuration list for PBXProject "Vector" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 53D1826C1F669CBB001F1840; + productRefGroup = 53D182761F669CBB001F1840 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 53D182741F669CBB001F1840 /* Vector */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 53D182731F669CBB001F1840 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53D182851F669CBB001F1840 /* LaunchScreen.storyboard in Resources */, + 53D182821F669CBB001F1840 /* Assets.xcassets in Resources */, + 53D182801F669CBB001F1840 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 53D182711F669CBB001F1840 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 53D182791F669CBB001F1840 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 53D1827E1F669CBB001F1840 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53D1827F1F669CBB001F1840 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 53D182831F669CBB001F1840 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53D182841F669CBB001F1840 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 53D182871F669CBB001F1840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 53D182881F669CBB001F1840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 53D1828A1F669CBB001F1840 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Vector/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Vector; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 53D1828B1F669CBB001F1840 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = LCC2J94N44; + INFOPLIST_FILE = Vector/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.useyourloaf.Vector; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 53D182701F669CBB001F1840 /* Build configuration list for PBXProject "Vector" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D182871F669CBB001F1840 /* Debug */, + 53D182881F669CBB001F1840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53D182891F669CBB001F1840 /* Build configuration list for PBXNativeTarget "Vector" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53D1828A1F669CBB001F1840 /* Debug */, + 53D1828B1F669CBB001F1840 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 53D1826D1F669CBB001F1840 /* Project object */; +} diff --git a/Vector/Vector/AppDelegate.swift b/Vector/Vector/AppDelegate.swift new file mode 100644 index 0000000..6420758 --- /dev/null +++ b/Vector/Vector/AppDelegate.swift @@ -0,0 +1,35 @@ +// Created by Keith Harrison https://useyourloaf.com +// Copyright (c) 2017 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? +} diff --git a/Vector/Vector/Assets.xcassets/AppIcon.appiconset/Contents.json b/Vector/Vector/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/Contents.json b/Vector/Vector/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/arrow-fill.imageset/Contents.json b/Vector/Vector/Assets.xcassets/arrow-fill.imageset/Contents.json new file mode 100644 index 0000000..b54f13d --- /dev/null +++ b/Vector/Vector/Assets.xcassets/arrow-fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow30-fill.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/arrow-fill.imageset/arrow30-fill.pdf b/Vector/Vector/Assets.xcassets/arrow-fill.imageset/arrow30-fill.pdf new file mode 100644 index 0000000..e218476 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/arrow-fill.imageset/arrow30-fill.pdf differ diff --git a/Vector/Vector/Assets.xcassets/arrow-large.imageset/Contents.json b/Vector/Vector/Assets.xcassets/arrow-large.imageset/Contents.json new file mode 100644 index 0000000..b54f13d --- /dev/null +++ b/Vector/Vector/Assets.xcassets/arrow-large.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow30-fill.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/arrow-large.imageset/arrow30-fill.pdf b/Vector/Vector/Assets.xcassets/arrow-large.imageset/arrow30-fill.pdf new file mode 100644 index 0000000..e218476 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/arrow-large.imageset/arrow30-fill.pdf differ diff --git a/Vector/Vector/Assets.xcassets/arrow.imageset/Contents.json b/Vector/Vector/Assets.xcassets/arrow.imageset/Contents.json new file mode 100644 index 0000000..cd093a4 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/arrow.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow30.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/arrow.imageset/arrow30.pdf b/Vector/Vector/Assets.xcassets/arrow.imageset/arrow30.pdf new file mode 100644 index 0000000..d1e947b Binary files /dev/null and b/Vector/Vector/Assets.xcassets/arrow.imageset/arrow30.pdf differ diff --git a/Vector/Vector/Assets.xcassets/cross-fill.imageset/Contents.json b/Vector/Vector/Assets.xcassets/cross-fill.imageset/Contents.json new file mode 100644 index 0000000..c4d92d6 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/cross-fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cross30-fill.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/cross-fill.imageset/cross30-fill.pdf b/Vector/Vector/Assets.xcassets/cross-fill.imageset/cross30-fill.pdf new file mode 100644 index 0000000..4a8a20b Binary files /dev/null and b/Vector/Vector/Assets.xcassets/cross-fill.imageset/cross30-fill.pdf differ diff --git a/Vector/Vector/Assets.xcassets/cross-large.imageset/Contents.json b/Vector/Vector/Assets.xcassets/cross-large.imageset/Contents.json new file mode 100644 index 0000000..a00e719 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/cross-large.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cross75.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/cross-large.imageset/cross75.pdf b/Vector/Vector/Assets.xcassets/cross-large.imageset/cross75.pdf new file mode 100644 index 0000000..7611740 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/cross-large.imageset/cross75.pdf differ diff --git a/Vector/Vector/Assets.xcassets/cross.imageset/Contents.json b/Vector/Vector/Assets.xcassets/cross.imageset/Contents.json new file mode 100644 index 0000000..1835714 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/cross.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cross30.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/cross.imageset/cross30.pdf b/Vector/Vector/Assets.xcassets/cross.imageset/cross30.pdf new file mode 100644 index 0000000..51eb165 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/cross.imageset/cross30.pdf differ diff --git a/Vector/Vector/Assets.xcassets/star-vector.imageset/Contents.json b/Vector/Vector/Assets.xcassets/star-vector.imageset/Contents.json new file mode 100644 index 0000000..3bc6cd0 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/star-vector.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star100.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/star-vector.imageset/star100.pdf b/Vector/Vector/Assets.xcassets/star-vector.imageset/star100.pdf new file mode 100644 index 0000000..ae25014 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/star-vector.imageset/star100.pdf differ diff --git a/Vector/Vector/Assets.xcassets/star.imageset/Contents.json b/Vector/Vector/Assets.xcassets/star.imageset/Contents.json new file mode 100644 index 0000000..0875f21 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/star.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star100.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/star.imageset/star100.pdf b/Vector/Vector/Assets.xcassets/star.imageset/star100.pdf new file mode 100644 index 0000000..ae25014 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/star.imageset/star100.pdf differ diff --git a/Vector/Vector/Assets.xcassets/tick-fill.imageset/Contents.json b/Vector/Vector/Assets.xcassets/tick-fill.imageset/Contents.json new file mode 100644 index 0000000..59e7bc9 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/tick-fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tick30-fill.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/tick-fill.imageset/tick30-fill.pdf b/Vector/Vector/Assets.xcassets/tick-fill.imageset/tick30-fill.pdf new file mode 100644 index 0000000..c3ac5b1 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/tick-fill.imageset/tick30-fill.pdf differ diff --git a/Vector/Vector/Assets.xcassets/tick-large.imageset/Contents.json b/Vector/Vector/Assets.xcassets/tick-large.imageset/Contents.json new file mode 100644 index 0000000..f323f00 --- /dev/null +++ b/Vector/Vector/Assets.xcassets/tick-large.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tick75.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/tick-large.imageset/tick75.pdf b/Vector/Vector/Assets.xcassets/tick-large.imageset/tick75.pdf new file mode 100644 index 0000000..1f3904c Binary files /dev/null and b/Vector/Vector/Assets.xcassets/tick-large.imageset/tick75.pdf differ diff --git a/Vector/Vector/Assets.xcassets/tick.imageset/Contents.json b/Vector/Vector/Assets.xcassets/tick.imageset/Contents.json new file mode 100644 index 0000000..266590c --- /dev/null +++ b/Vector/Vector/Assets.xcassets/tick.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tick30.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "preserves-vector-representation" : true + } +} \ No newline at end of file diff --git a/Vector/Vector/Assets.xcassets/tick.imageset/tick30.pdf b/Vector/Vector/Assets.xcassets/tick.imageset/tick30.pdf new file mode 100644 index 0000000..4249d58 Binary files /dev/null and b/Vector/Vector/Assets.xcassets/tick.imageset/tick30.pdf differ diff --git a/Vector/Vector/Base.lproj/LaunchScreen.storyboard b/Vector/Vector/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f83f6fd --- /dev/null +++ b/Vector/Vector/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vector/Vector/Base.lproj/Main.storyboard b/Vector/Vector/Base.lproj/Main.storyboard new file mode 100644 index 0000000..4c052d6 --- /dev/null +++ b/Vector/Vector/Base.lproj/Main.storyboard @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vector/Vector/Info.plist b/Vector/Vector/Info.plist new file mode 100644 index 0000000..6873106 --- /dev/null +++ b/Vector/Vector/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/WorldFacts/Default-568h@2x.png b/WorldFacts/Default-568h@2x.png deleted file mode 100644 index 6133557..0000000 Binary files a/WorldFacts/Default-568h@2x.png and /dev/null differ diff --git a/WorldFacts/Default.png b/WorldFacts/Default.png deleted file mode 100644 index 0bb331c..0000000 Binary files a/WorldFacts/Default.png and /dev/null differ diff --git a/WorldFacts/Default@2x.png b/WorldFacts/Default@2x.png deleted file mode 100644 index 0d5eccd..0000000 Binary files a/WorldFacts/Default@2x.png and /dev/null differ diff --git a/WorldFacts/Icon@2x.png b/WorldFacts/Icon@2x.png deleted file mode 100644 index 8e3ed04..0000000 Binary files a/WorldFacts/Icon@2x.png and /dev/null differ diff --git a/WorldFacts/README b/WorldFacts/README deleted file mode 100644 index b82ab91..0000000 --- a/WorldFacts/README +++ /dev/null @@ -1,115 +0,0 @@ -======================================================================= -WorldFacts - -Version 1.5 20 Feb 2013 Move core data file to App Support dir -Version 1.4 31 Dec 2012 Add default launch images to support retina - 4 inch display -Version 1.3 6 Sep 2012 Add a search bar -Version 1.2 1 Aug 2012 Use default synthesis of ivars -Version 1.1 21 June 2012 Add Storyboard segue to country view -Version 1.0 6 June 2012 Initial Version -======================================================================= - -The WorldFacts App demonstrates how to use Storyboards to create a -dynamic table view cell using a prototype cell. This is a big -improvement over iOS 4 where it was necessary to design the cell -in a separate NIB and then manually load it and instantiate each -cell. - -For further details see: - -useyourloaf.com/blog/2012/06/07/prototype-cells-and-storyboards.html - -For details on adding a storyboard segue to show the country detailed -view see the following post: - -useyourloaf.com/blog/2012/06/21/storyboard-segues.html - -The steps to add a search bar to the table view controller are covered -in the following post: - -useyourloaf.com/blog/2012/09/06/search-bar-table-view-storyboard.html - -The geographic data used in this App is from GeoNames and used under -the Creative Commons Attributions License (see www.geonames.org). - - -======================================================================= -Model -======================================================================= - -WorldFacts.xcdatamodeld - -The core data model definition contains a single entity for the Country -managed object. - -Country.h -Country.m - -The generated NSManagedObject subclass - -Country+Extensions.h -Country+Extensions.m - -Private class extensions for the Country NSManagedObject subclass to -generate the section title used by the NSFetchedResultsController and -to import an initial set of geographic data from countries.plist. - -======================================================================= -View -======================================================================= - -Country.storyboard -The storyboard file used to create the table view and custom prototype -cell. - -UYLCountryTableViewController.xib -Traditional NIB file used to load the country table view when not using -a storyboard. This NIB file is not used in the final version of the App -but is included for reference. If you want to revert back to -using this NIB you will need to add it to the target. - -CountryCell.xib -Traditional NIB file used to create the custom table view cell when not -using a storyboard. This NIB file is not used in the final version of -the App but is included for reference. If you want to revert back to -using this NIB you will need to add it to the target. - -UYLCountryViewController.xib -Traditional NIB file used to show the country detail view when not using -a storyboard. This NIB file is not used in the final version of the App -but is included for reference. If you want to revert back to using this -NIB you will need to add it to the target. - -======================================================================= -Controllers -======================================================================= - -UYLCountryTableViewController.h -UYLCountryTableViewController.m - -The table view controller used to show the list of countries with -details on the capital and population in a custom cell layout. The -table view controller implementation is a standard implementation of -an NSFetchResultsController. - -The key code showing how the cell NIB is loaded is contained in the -method -tableView:cellForRowAtIndexPath:. - -UYLCountryViewController.h -UYLCountryViewController.m - -The view controller used to show the detailed country view. This view -controller does almost nothing other than set up the view from the -Country object it is passed. - -======================================================================= -App Delegate -======================================================================= - -UYLAppDelegate.h -UYLAppDelegate.m - -The App delegate is largely unmodified from the template code. It creates -the root view controller using a storyboard and initialises the core data -stack. \ No newline at end of file diff --git a/WorldFacts/README.md b/WorldFacts/README.md new file mode 100644 index 0000000..f108fed --- /dev/null +++ b/WorldFacts/README.md @@ -0,0 +1,118 @@ +## WorldFacts + +The WorldFacts App has gone through a number of iterations over the +years as the capabilities of iOS have changed. Originally it started +as an example of how to construct custom table view cells with a +storyboard. Some of the earlier posts are likely only of historical interest +now but I think it is interesting to show how much iOS apps need to change +over the years. + +For further details see the following posts: + +* [Prototype Table Cells and Storyboards](https://useyourloaf.com/blog/prototype-table-cells-and-storyboards/) + +For details on adding a storyboard segue to show the country detailed +view see the following post: + +* [Storyboard Segues](https://useyourloaf.com/blog/storyboard-segues/) + +The steps to add a search bar to the table view controller are covered +in the following post: + +* [Adding A Search Bar To A Table View With Storyboards](https://useyourloaf.com/blog/search-bar-table-view-storyboard/) + +The release of iOS 8 saw a number of changes to update and modernise +the code: + ++ UISearchDisplayController is deprecated and replaced by the much + cleaner UISearchController ++ Modules are now used instead of precompiled headers ++ The Storyboard is now universal ++ Include a launch screen storyboard ++ Autolayout is used ++ Dynamic Type is used for the content ++ Asset Catalogs for the icons and images ++ Base Internationalization ++ Remove old orientation handling code. + +An OS X companion app has also been added to create and maintain the core +data stack. Full details on how to use Cocoa Bindings to create a simple +interface to Core Data are covered in the following post: + +* [Creating an OS X Core Data Helper App](https://useyourloaf.com/blog/creating-an-os-x-core-data-helper-app/) + +To see details on how to increase the width of the master view of the split +view controller see the following post: + +* [Change the Width of Master View in Split View Controller](https://useyourloaf.com//blog/change-the-width-of-master-view-in-split-view-controller/) + +The geographic data used in this App is from GeoNames and used under +the Creative Commons Attributions License. See [www.geonames.org](www.geonames.org). + + +### Model + +* `WorldFacts.xcdatamodeld` + + The core data model definition contains a single entity for the Country +managed object. + +* `Country.h` +* `Country.m` + + The generated `NSManagedObject` subclass + +* `Country+Extensions.h` +* `Country+Extensions.m` + + Private class extensions for the Country NSManagedObject subclass to +generate the section title used by the NSFetchedResultsController and +to import an initial set of geographic data from countries.plist. + +### View + +* `Main.storyboard` + + The universal storyboard file used to create the table and details view + +### Controllers + +* `UYLCountryTableViewController.h` +* `UYLCountryTableViewController.m` + + The table view controller used to show the list of countries with +details on the capital and population and manage the search interface. +The table view controller implementation is a standard implementation +of an `NSFetchResultsController`. + +* `UYLCountryViewController.h` +* `UYLCountryViewController.m` + + The view controller used to show the detailed country view. This view +controller does almost nothing other than set up the view from the +Country object it is passed. + +### App Delegate + +* `UYLAppDelegate.h` +* `UYLAppDelegate.m` + + The App delegate is largely unmodified from the template code. It creates +the root view controller using a storyboard and initialises the core data +stack. + +### Version History + +Version 3.3 19 Jan 2018 Update for Xcode 9, minimum target is iOS 9 +Version 3.2 12 Oct 2015 Add 3D Touch peek and pop preview +Version 3.1 25 May 2015 Increase width of split view master view +Version 3.0 27 Mar 2015 Add OS X application to create core data +Version 2.0 16 Feb 2014 Update for iOS 8 and UISearchController +Version 1.5 20 Feb 2013 Move core data file to App Support dir +Version 1.4 31 Dec 2012 Add default launch images to support retina +4 inch display +Version 1.3 6 Sep 2012 Add a search bar +Version 1.2 1 Aug 2012 Use default synthesis of ivars +Version 1.1 21 June 2012 Add Storyboard segue to country view +Version 1.0 6 June 2012 Initial Version + diff --git a/WorldFacts/WorldFacts.xcodeproj/project.pbxproj b/WorldFacts/WorldFacts.xcodeproj/project.pbxproj index 5b9b89f..dc570e8 100644 --- a/WorldFacts/WorldFacts.xcodeproj/project.pbxproj +++ b/WorldFacts/WorldFacts.xcodeproj/project.pbxproj @@ -3,107 +3,121 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ - 532CADEB158D1286002BEDC8 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 532CADEA158D1286002BEDC8 /* README */; }; + 5313456D1ABF5FFE000B013F /* CountryWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5313456C1ABF5FFE000B013F /* CountryWindowController.m */; }; + 531D96131AB62FEF00913A78 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 531D96121AB62FEF00913A78 /* AppDelegate.m */; }; + 531D96151AB62FEF00913A78 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 531D96141AB62FEF00913A78 /* main.m */; }; + 531D961D1AB62FEF00913A78 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 531D961C1AB62FEF00913A78 /* Images.xcassets */; }; + 531D96201AB62FEF00913A78 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 531D961E1AB62FEF00913A78 /* Main.storyboard */; }; 532CADF5158D19D1002BEDC8 /* UYLCountryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 532CADF4158D19D1002BEDC8 /* UYLCountryViewController.m */; }; - 53524B401691E77100719AF8 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B391691E77100719AF8 /* Default-568h@2x.png */; }; - 53524B411691E77100719AF8 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3A1691E77100719AF8 /* Default.png */; }; - 53524B421691E77100719AF8 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3B1691E77100719AF8 /* Default@2x.png */; }; - 53524B431691E77100719AF8 /* Icon-Small.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3C1691E77100719AF8 /* Icon-Small.png */; }; - 53524B441691E77100719AF8 /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3D1691E77100719AF8 /* Icon-Small@2x.png */; }; - 53524B451691E77100719AF8 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3E1691E77100719AF8 /* Icon.png */; }; - 53524B461691E77100719AF8 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 53524B3F1691E77100719AF8 /* Icon@2x.png */; }; - 538A797D157E567F0007B8A5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538A797C157E567F0007B8A5 /* UIKit.framework */; }; - 538A797F157E567F0007B8A5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538A797E157E567F0007B8A5 /* Foundation.framework */; }; - 538A7981157E567F0007B8A5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538A7980157E567F0007B8A5 /* CoreGraphics.framework */; }; - 538A7983157E567F0007B8A5 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538A7982157E567F0007B8A5 /* CoreData.framework */; }; - 538A7989157E567F0007B8A5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 538A7987157E567F0007B8A5 /* InfoPlist.strings */; }; + 534EBDA01AC4B0F90014AD9D /* WorldFacts.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 534EBD9F1AC4B0F90014AD9D /* WorldFacts.sqlite */; }; + 536346AE1AC0BE440087214A /* CountryTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 536346AD1AC0BE440087214A /* CountryTableViewController.m */; }; + 536346AF1AC0CC980087214A /* Country.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A87BF0157FAD42000DBAC9 /* Country.m */; }; + 536346B01AC0CC9C0087214A /* Country+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A87BE6157FA30A000DBAC9 /* Country+Extensions.m */; }; + 536346B11AC0D4570087214A /* countries.plist in Resources */ = {isa = PBXBuildFile; fileRef = 538A79B1157E80D40007B8A5 /* countries.plist */; }; 538A798B157E567F0007B8A5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 538A798A157E567F0007B8A5 /* main.m */; }; 538A798F157E567F0007B8A5 /* UYLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 538A798E157E567F0007B8A5 /* UYLAppDelegate.m */; }; 538A7992157E567F0007B8A5 /* WorldFacts.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 538A7990157E567F0007B8A5 /* WorldFacts.xcdatamodeld */; }; 538A79A4157E5A730007B8A5 /* UYLCountryTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 538A79A3157E5A730007B8A5 /* UYLCountryTableViewController.m */; }; - 538A79A9157E5ABD0007B8A5 /* Country.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 538A79A8157E5ABD0007B8A5 /* Country.storyboard */; }; - 538A79B2157E80D40007B8A5 /* countries.plist in Resources */ = {isa = PBXBuildFile; fileRef = 538A79B1157E80D40007B8A5 /* countries.plist */; }; + 539851C21ABB76EA00A5598B /* WorldFacts.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 538A7990157E567F0007B8A5 /* WorldFacts.xcdatamodeld */; }; 53A87BE7157FA30A000DBAC9 /* Country+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A87BE6157FA30A000DBAC9 /* Country+Extensions.m */; }; 53A87BF1157FAD42000DBAC9 /* Country.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A87BF0157FAD42000DBAC9 /* Country.m */; }; - 53AE171015FA5BBE00911A7C /* CountryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53A87BFA157FD530000DBAC9 /* CountryCell.xib */; }; + 53B691731A3A5AE500DDFBE2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53B691751A3A5AE500DDFBE2 /* Localizable.strings */; }; + 53E7826D1A3658590075A619 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 53E7826C1A3658590075A619 /* Images.xcassets */; }; + 53E782701A365AE60075A619 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53E782721A365AE60075A619 /* Main.storyboard */; }; + 53EDC9911A37AF03005CDB68 /* CountryCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDC9901A37AF03005CDB68 /* CountryCell.m */; }; + 53EEC7E71A4B6254000EB901 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 53EEC7E61A4B6254000EB901 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 532CADEA158D1286002BEDC8 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 532CADF0158D1690002BEDC8 /* UYLCountryViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UYLCountryViewController.xib; sourceTree = ""; }; + 5313456B1ABF5FFE000B013F /* CountryWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CountryWindowController.h; sourceTree = ""; }; + 5313456C1ABF5FFE000B013F /* CountryWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CountryWindowController.m; sourceTree = ""; }; + 531D960D1AB62FEF00913A78 /* WorldFactsBuilder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WorldFactsBuilder.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 531D96101AB62FEF00913A78 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 531D96111AB62FEF00913A78 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 531D96121AB62FEF00913A78 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 531D96141AB62FEF00913A78 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 531D961C1AB62FEF00913A78 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 531D961F1AB62FEF00913A78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 532CADEA158D1286002BEDC8 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 532CADF3158D19D1002BEDC8 /* UYLCountryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLCountryViewController.h; sourceTree = ""; }; 532CADF4158D19D1002BEDC8 /* UYLCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLCountryViewController.m; sourceTree = ""; }; - 53524B391691E77100719AF8 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; - 53524B3A1691E77100719AF8 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; - 53524B3B1691E77100719AF8 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; - 53524B3C1691E77100719AF8 /* Icon-Small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small.png"; sourceTree = ""; }; - 53524B3D1691E77100719AF8 /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = ""; }; - 53524B3E1691E77100719AF8 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; - 53524B3F1691E77100719AF8 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = ""; }; + 534EBD9F1AC4B0F90014AD9D /* WorldFacts.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = WorldFacts.sqlite; sourceTree = ""; }; + 536346AC1AC0BE440087214A /* CountryTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CountryTableViewController.h; sourceTree = ""; }; + 536346AD1AC0BE440087214A /* CountryTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CountryTableViewController.m; sourceTree = ""; }; 538A7978157E567F0007B8A5 /* WorldFacts.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WorldFacts.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 538A797C157E567F0007B8A5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 538A797E157E567F0007B8A5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 538A7980157E567F0007B8A5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 538A7982157E567F0007B8A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 538A7986157E567F0007B8A5 /* WorldFacts-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "WorldFacts-Info.plist"; sourceTree = ""; }; - 538A7988157E567F0007B8A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 538A798A157E567F0007B8A5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 538A798C157E567F0007B8A5 /* WorldFacts-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WorldFacts-Prefix.pch"; sourceTree = ""; }; 538A798D157E567F0007B8A5 /* UYLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UYLAppDelegate.h; sourceTree = ""; }; 538A798E157E567F0007B8A5 /* UYLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UYLAppDelegate.m; sourceTree = ""; }; 538A7991157E567F0007B8A5 /* WorldFacts.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = WorldFacts.xcdatamodel; sourceTree = ""; }; 538A79A2157E5A730007B8A5 /* UYLCountryTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UYLCountryTableViewController.h; sourceTree = ""; }; 538A79A3157E5A730007B8A5 /* UYLCountryTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UYLCountryTableViewController.m; sourceTree = ""; }; - 538A79A8157E5ABD0007B8A5 /* Country.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Country.storyboard; sourceTree = ""; }; 538A79B1157E80D40007B8A5 /* countries.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = countries.plist; sourceTree = ""; }; 53A87BE5157FA30A000DBAC9 /* Country+Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Country+Extensions.h"; sourceTree = ""; }; 53A87BE6157FA30A000DBAC9 /* Country+Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Country+Extensions.m"; sourceTree = ""; }; 53A87BEF157FAD42000DBAC9 /* Country.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Country.h; sourceTree = ""; }; 53A87BF0157FAD42000DBAC9 /* Country.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Country.m; sourceTree = ""; }; - 53A87BF8157FC55A000DBAC9 /* UYLCountryTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UYLCountryTableViewController.xib; sourceTree = ""; }; - 53A87BFA157FD530000DBAC9 /* CountryCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CountryCell.xib; sourceTree = ""; }; + 53B691741A3A5AE500DDFBE2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 53E7826C1A3658590075A619 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 53E782731A365AF30075A619 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 53EDC98F1A37AF03005CDB68 /* CountryCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CountryCell.h; sourceTree = ""; }; + 53EDC9901A37AF03005CDB68 /* CountryCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CountryCell.m; sourceTree = ""; }; + 53EEC7E61A4B6254000EB901 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 531D960A1AB62FEF00913A78 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 538A7975157E567F0007B8A5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 538A797D157E567F0007B8A5 /* UIKit.framework in Frameworks */, - 538A797F157E567F0007B8A5 /* Foundation.framework in Frameworks */, - 538A7981157E567F0007B8A5 /* CoreGraphics.framework in Frameworks */, - 538A7983157E567F0007B8A5 /* CoreData.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 53524B241691D45C00719AF8 /* Resources */ = { + 531D960E1AB62FEF00913A78 /* WorldFactsBuilder */ = { isa = PBXGroup; children = ( - 53524B391691E77100719AF8 /* Default-568h@2x.png */, - 53524B3A1691E77100719AF8 /* Default.png */, - 53524B3B1691E77100719AF8 /* Default@2x.png */, - 53524B3C1691E77100719AF8 /* Icon-Small.png */, - 53524B3D1691E77100719AF8 /* Icon-Small@2x.png */, - 53524B3E1691E77100719AF8 /* Icon.png */, - 53524B3F1691E77100719AF8 /* Icon@2x.png */, + 531D96111AB62FEF00913A78 /* AppDelegate.h */, + 531D96121AB62FEF00913A78 /* AppDelegate.m */, + 5313456B1ABF5FFE000B013F /* CountryWindowController.h */, + 5313456C1ABF5FFE000B013F /* CountryWindowController.m */, + 536346AC1AC0BE440087214A /* CountryTableViewController.h */, + 536346AD1AC0BE440087214A /* CountryTableViewController.m */, + 531D961C1AB62FEF00913A78 /* Images.xcassets */, + 531D961E1AB62FEF00913A78 /* Main.storyboard */, + 531D960F1AB62FEF00913A78 /* Supporting Files */, ); - name = Resources; - path = ..; + path = WorldFactsBuilder; + sourceTree = ""; + }; + 531D960F1AB62FEF00913A78 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 531D96101AB62FEF00913A78 /* Info.plist */, + 531D96141AB62FEF00913A78 /* main.m */, + ); + name = "Supporting Files"; sourceTree = ""; }; 538A796D157E567E0007B8A5 = { isa = PBXGroup; children = ( - 532CADEA158D1286002BEDC8 /* README */, + 532CADEA158D1286002BEDC8 /* README.md */, 538A7984157E567F0007B8A5 /* WorldFacts */, - 538A797B157E567F0007B8A5 /* Frameworks */, + 531D960E1AB62FEF00913A78 /* WorldFactsBuilder */, 538A7979157E567F0007B8A5 /* Products */, ); sourceTree = ""; @@ -112,21 +126,11 @@ isa = PBXGroup; children = ( 538A7978157E567F0007B8A5 /* WorldFacts.app */, + 531D960D1AB62FEF00913A78 /* WorldFactsBuilder.app */, ); name = Products; sourceTree = ""; }; - 538A797B157E567F0007B8A5 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 538A797C157E567F0007B8A5 /* UIKit.framework */, - 538A797E157E567F0007B8A5 /* Foundation.framework */, - 538A7980157E567F0007B8A5 /* CoreGraphics.framework */, - 538A7982157E567F0007B8A5 /* CoreData.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 538A7984157E567F0007B8A5 /* WorldFacts */ = { isa = PBXGroup; children = ( @@ -136,7 +140,7 @@ 538A799A157E56BF0007B8A5 /* Views */, 538A7998157E56A30007B8A5 /* Controllers */, 538A7985157E567F0007B8A5 /* Supporting Files */, - 53524B241691D45C00719AF8 /* Resources */, + 53E7826C1A3658590075A619 /* Images.xcassets */, ); path = WorldFacts; sourceTree = ""; @@ -144,11 +148,11 @@ 538A7985157E567F0007B8A5 /* Supporting Files */ = { isa = PBXGroup; children = ( + 534EBD9F1AC4B0F90014AD9D /* WorldFacts.sqlite */, 538A79B1157E80D40007B8A5 /* countries.plist */, 538A7986157E567F0007B8A5 /* WorldFacts-Info.plist */, - 538A7987157E567F0007B8A5 /* InfoPlist.strings */, 538A798A157E567F0007B8A5 /* main.m */, - 538A798C157E567F0007B8A5 /* WorldFacts-Prefix.pch */, + 53B691751A3A5AE500DDFBE2 /* Localizable.strings */, ); name = "Supporting Files"; sourceTree = ""; @@ -179,10 +183,10 @@ 538A799A157E56BF0007B8A5 /* Views */ = { isa = PBXGroup; children = ( - 538A79A8157E5ABD0007B8A5 /* Country.storyboard */, - 53A87BF8157FC55A000DBAC9 /* UYLCountryTableViewController.xib */, - 53A87BFA157FD530000DBAC9 /* CountryCell.xib */, - 532CADF0158D1690002BEDC8 /* UYLCountryViewController.xib */, + 53E782721A365AE60075A619 /* Main.storyboard */, + 53EEC7E61A4B6254000EB901 /* LaunchScreen.storyboard */, + 53EDC98F1A37AF03005CDB68 /* CountryCell.h */, + 53EDC9901A37AF03005CDB68 /* CountryCell.m */, ); name = Views; sourceTree = ""; @@ -190,6 +194,23 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 531D960C1AB62FEF00913A78 /* WorldFactsBuilder */ = { + isa = PBXNativeTarget; + buildConfigurationList = 531D96311AB62FEF00913A78 /* Build configuration list for PBXNativeTarget "WorldFactsBuilder" */; + buildPhases = ( + 531D96091AB62FEF00913A78 /* Sources */, + 531D960A1AB62FEF00913A78 /* Frameworks */, + 531D960B1AB62FEF00913A78 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WorldFactsBuilder; + productName = WorldFactsBuilder; + productReference = 531D960D1AB62FEF00913A78 /* WorldFactsBuilder.app */; + productType = "com.apple.product-type.application"; + }; 538A7977157E567F0007B8A5 /* WorldFacts */ = { isa = PBXNativeTarget; buildConfigurationList = 538A7995157E567F0007B8A5 /* Build configuration list for PBXNativeTarget "WorldFacts" */; @@ -214,14 +235,23 @@ isa = PBXProject; attributes = { CLASSPREFIX = UYL; - LastUpgradeCheck = 0460; + LastUpgradeCheck = 1100; + TargetAttributes = { + 531D960C1AB62FEF00913A78 = { + CreatedOnToolsVersion = 6.2; + }; + 538A7977157E567F0007B8A5 = { + DevelopmentTeam = LCC2J94N44; + }; + }; }; buildConfigurationList = 538A7972157E567E0007B8A5 /* Build configuration list for PBXProject "WorldFacts" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 538A796D157E567E0007B8A5; productRefGroup = 538A7979157E567F0007B8A5 /* Products */; @@ -229,33 +259,51 @@ projectRoot = ""; targets = ( 538A7977157E567F0007B8A5 /* WorldFacts */, + 531D960C1AB62FEF00913A78 /* WorldFactsBuilder */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 531D960B1AB62FEF00913A78 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 531D961D1AB62FEF00913A78 /* Images.xcassets in Resources */, + 531D96201AB62FEF00913A78 /* Main.storyboard in Resources */, + 536346B11AC0D4570087214A /* countries.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 538A7976157E567F0007B8A5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 538A7989157E567F0007B8A5 /* InfoPlist.strings in Resources */, - 538A79A9157E5ABD0007B8A5 /* Country.storyboard in Resources */, - 538A79B2157E80D40007B8A5 /* countries.plist in Resources */, - 532CADEB158D1286002BEDC8 /* README in Resources */, - 53AE171015FA5BBE00911A7C /* CountryCell.xib in Resources */, - 53524B401691E77100719AF8 /* Default-568h@2x.png in Resources */, - 53524B411691E77100719AF8 /* Default.png in Resources */, - 53524B421691E77100719AF8 /* Default@2x.png in Resources */, - 53524B431691E77100719AF8 /* Icon-Small.png in Resources */, - 53524B441691E77100719AF8 /* Icon-Small@2x.png in Resources */, - 53524B451691E77100719AF8 /* Icon.png in Resources */, - 53524B461691E77100719AF8 /* Icon@2x.png in Resources */, + 534EBDA01AC4B0F90014AD9D /* WorldFacts.sqlite in Resources */, + 53E7826D1A3658590075A619 /* Images.xcassets in Resources */, + 53B691731A3A5AE500DDFBE2 /* Localizable.strings in Resources */, + 53E782701A365AE60075A619 /* Main.storyboard in Resources */, + 53EEC7E71A4B6254000EB901 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 531D96091AB62FEF00913A78 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 536346AF1AC0CC980087214A /* Country.m in Sources */, + 5313456D1ABF5FFE000B013F /* CountryWindowController.m in Sources */, + 531D96151AB62FEF00913A78 /* main.m in Sources */, + 536346AE1AC0BE440087214A /* CountryTableViewController.m in Sources */, + 539851C21ABB76EA00A5598B /* WorldFacts.xcdatamodeld in Sources */, + 536346B01AC0CC9C0087214A /* Country+Extensions.m in Sources */, + 531D96131AB62FEF00913A78 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 538A7974157E567F0007B8A5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -264,6 +312,7 @@ 538A798F157E567F0007B8A5 /* UYLAppDelegate.m in Sources */, 538A7992157E567F0007B8A5 /* WorldFacts.xcdatamodeld in Sources */, 538A79A4157E5A730007B8A5 /* UYLCountryTableViewController.m in Sources */, + 53EDC9911A37AF03005CDB68 /* CountryCell.m in Sources */, 53A87BE7157FA30A000DBAC9 /* Country+Extensions.m in Sources */, 53A87BF1157FAD42000DBAC9 /* Country.m in Sources */, 532CADF5158D19D1002BEDC8 /* UYLCountryViewController.m in Sources */, @@ -273,32 +322,120 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 538A7987157E567F0007B8A5 /* InfoPlist.strings */ = { + 531D961E1AB62FEF00913A78 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( - 538A7988157E567F0007B8A5 /* en */, + 531D961F1AB62FEF00913A78 /* Base */, ); - name = InfoPlist.strings; + name = Main.storyboard; + sourceTree = ""; + }; + 53B691751A3A5AE500DDFBE2 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 53B691741A3A5AE500DDFBE2 /* en */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 53E782721A365AE60075A619 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 53E782731A365AF30075A619 /* Base */, + ); + name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 531D962D1AB62FEF00913A78 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = WorldFactsBuilder/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 531D962E1AB62FEF00913A78 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = WorldFactsBuilder/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; 538A7993157E567F0007B8A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Keith Harrison (WT6HWP7T28)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -306,11 +443,16 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "E74808E4-A667-47F3-9D3D-467AE6C6A08A"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; SDKROOT = iphoneos; }; name = Debug; @@ -319,23 +461,45 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Keith Harrison (WT6HWP7T28)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 5.1; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "74BAAD79-977D-4BCF-BDFF-9A8D817AF82E"; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; @@ -344,10 +508,15 @@ 538A7996157E567F0007B8A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WorldFacts/WorldFacts-Prefix.pch"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 12; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = "WorldFacts/WorldFacts-Info.plist"; + MARKETING_VERSION = 3.4; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -355,10 +524,15 @@ 538A7997157E567F0007B8A5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "WorldFacts/WorldFacts-Prefix.pch"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 12; + DEVELOPMENT_TEAM = LCC2J94N44; + GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = "WorldFacts/WorldFacts-Info.plist"; + MARKETING_VERSION = 3.4; + PRODUCT_BUNDLE_IDENTIFIER = "com.useyourloaf.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Release; @@ -366,6 +540,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 531D96311AB62FEF00913A78 /* Build configuration list for PBXNativeTarget "WorldFactsBuilder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 531D962D1AB62FEF00913A78 /* Debug */, + 531D962E1AB62FEF00913A78 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 538A7972157E567E0007B8A5 /* Build configuration list for PBXProject "WorldFacts" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/WorldFacts/WorldFacts/Base.lproj/InfoPlist.strings b/WorldFacts/WorldFacts/Base.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/WorldFacts/WorldFacts/Base.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/WorldFacts/WorldFacts/Base.lproj/Main.storyboard b/WorldFacts/WorldFacts/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2cdc686 --- /dev/null +++ b/WorldFacts/WorldFacts/Base.lproj/Main.storyboard @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WorldFacts/WorldFacts/Country.storyboard b/WorldFacts/WorldFacts/Country.storyboard deleted file mode 100644 index 2fece73..0000000 --- a/WorldFacts/WorldFacts/Country.storyboard +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - Country - Capital - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WorldFacts/WorldFacts/CountryCell.h b/WorldFacts/WorldFacts/CountryCell.h new file mode 100644 index 0000000..d79ed4c --- /dev/null +++ b/WorldFacts/WorldFacts/CountryCell.h @@ -0,0 +1,43 @@ +// +// CountryCellTableViewCell.h +// WorldFacts2 +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface CountryCell : UITableViewCell + +@property (copy, nonatomic) NSString *name; +@property (copy, nonatomic) NSString *capital; +@property (copy, nonatomic) NSString *population; + +@end diff --git a/WorldFacts/WorldFacts/CountryCell.m b/WorldFacts/WorldFacts/CountryCell.m new file mode 100644 index 0000000..5fdb430 --- /dev/null +++ b/WorldFacts/WorldFacts/CountryCell.m @@ -0,0 +1,69 @@ +// +// CountryCellTableViewCell.m +// WorldFacts2 +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2014 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "CountryCell.h" + +@interface CountryCell () +@property (weak, nonatomic) IBOutlet UILabel *countryLabel; +@property (weak, nonatomic) IBOutlet UILabel *capitalLabel; +@property (weak, nonatomic) IBOutlet UILabel *populationLabel; +@end + +@implementation CountryCell + +- (void)setName:(NSString *)name { + if (_name != name) { + _name = [name copy]; + _countryLabel.text =_name; + _countryLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + } +} + +- (void)setCapital:(NSString *)capital { + if (_capital != capital) { + _capital = [capital copy]; + _capitalLabel.text =_capital; + _capitalLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; + } +} + +- (void)setPopulation:(NSString *)population { + if (_population != population) { + _population = [population copy]; + _populationLabel.text =_population; + _populationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; + } +} + +@end diff --git a/WorldFacts/WorldFacts/CountryCell.xib b/WorldFacts/WorldFacts/CountryCell.xib deleted file mode 100644 index 4544f1e..0000000 --- a/WorldFacts/WorldFacts/CountryCell.xib +++ /dev/null @@ -1,263 +0,0 @@ - - - - 1296 - 12B19 - 2549 - 1187 - 624.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1498 - - - IBProxyObject - IBUILabel - IBUITableViewCell - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - - - 256 - - - - 292 - {{20, 7}, {280, 26}} - - - _NS:9 - NO - YES - 7 - 100 - NO - IBCocoaTouchFramework - Country - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 3 - MQA - - 0 - 10 - - 2 - 14 - - - Helvetica-Bold - 14 - 16 - - - - - 292 - {{20, 33}, {140, 21}} - - - _NS:9 - NO - YES - 7 - 200 - NO - IBCocoaTouchFramework - Capital - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 12 - - 1 - 12 - - - Helvetica - 12 - 16 - - - - - 289 - {{160, 33}, {130, 21}} - - _NS:9 - NO - YES - 7 - 300 - NO - IBCocoaTouchFramework - Pop: 1,234,567,890 - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 12 - 2 - - - - - {320, 63} - - - _NS:11 - - 3 - MCAwAA - - NO - YES - 4 - YES - IBCocoaTouchFramework - - - {320, 64} - - - _NS:9 - IBCocoaTouchFramework - - UYLNibCountryCellIdentifier - - - - - - - - countryCell - - - - 8 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - - - - 3 - - - - - 4 - - - - - 5 - - - - - - - UYLCountryTableViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 8 - - - - - UYLCountryTableViewController - UITableViewController - - countryCell - UITableViewCell - - - countryCell - - countryCell - UITableViewCell - - - - IBProjectSource - ./Classes/UYLCountryTableViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1498 - - diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Contents.json b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..c3a6f2d --- /dev/null +++ b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon2-20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon2-20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon2-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-80-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon2-60@2x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-120.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-180.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon2-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon2-20@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-80.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-152.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon2-835@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon2-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-120.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-120.png new file mode 100644 index 0000000..4220c9e Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-120.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-180.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-180.png new file mode 100644 index 0000000..5620b17 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-180.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-40.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-40.png new file mode 100644 index 0000000..c43dfbd Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-40.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-76.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 0000000..1f423df Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80-1.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80-1.png new file mode 100644 index 0000000..99143c1 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80-1.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80.png new file mode 100644 index 0000000..99143c1 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-80.png differ diff --git a/WorldFacts/Icon-Small.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-Small.png similarity index 100% rename from WorldFacts/Icon-Small.png rename to WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-Small.png diff --git a/WorldFacts/Icon-Small@2x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png similarity index 100% rename from WorldFacts/Icon-Small@2x.png rename to WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png new file mode 100644 index 0000000..d828562 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-29@3x.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-60@2x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-60@2x.png new file mode 100644 index 0000000..ffb0d74 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-60@2x.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png new file mode 100644 index 0000000..eb4d728 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/Icon2-835@2x.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon-152.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon-152.png new file mode 100644 index 0000000..ad2f3fd Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon-152.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-1024.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-1024.png new file mode 100644 index 0000000..b628b9e Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-1024.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20.png new file mode 100644 index 0000000..08dee7a Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png new file mode 100644 index 0000000..d6fccd4 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x-1.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png new file mode 100644 index 0000000..d6fccd4 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@2x.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png new file mode 100644 index 0000000..fafe147 Binary files /dev/null and b/WorldFacts/WorldFacts/Images.xcassets/AppIcon.appiconset/icon2-20@3x.png differ diff --git a/WorldFacts/WorldFacts/Images.xcassets/Contents.json b/WorldFacts/WorldFacts/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/WorldFacts/WorldFacts/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/WorldFacts/WorldFacts/LaunchScreen.storyboard b/WorldFacts/WorldFacts/LaunchScreen.storyboard new file mode 100644 index 0000000..fe2e48d --- /dev/null +++ b/WorldFacts/WorldFacts/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WorldFacts/WorldFacts/LaunchScreen.xib b/WorldFacts/WorldFacts/LaunchScreen.xib new file mode 100644 index 0000000..6eafd7f --- /dev/null +++ b/WorldFacts/WorldFacts/LaunchScreen.xib @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WorldFacts/WorldFacts/UYLAppDelegate.h b/WorldFacts/WorldFacts/UYLAppDelegate.h index 87acad6..ee88f0f 100644 --- a/WorldFacts/WorldFacts/UYLAppDelegate.h +++ b/WorldFacts/WorldFacts/UYLAppDelegate.h @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2014 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -40,7 +40,4 @@ @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; -- (void)saveContext; -- (NSURL *)applicationSupportDirectory; - @end diff --git a/WorldFacts/WorldFacts/UYLAppDelegate.m b/WorldFacts/WorldFacts/UYLAppDelegate.m index 28b1559..d6fd8e0 100644 --- a/WorldFacts/WorldFacts/UYLAppDelegate.m +++ b/WorldFacts/WorldFacts/UYLAppDelegate.m @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2015 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -32,14 +32,17 @@ #import "UYLAppDelegate.h" #import "UYLCountryTableViewController.h" +#import "UYLCountryViewController.h" #import "Country+Extensions.h" +@interface UYLAppDelegate () +@end + @implementation UYLAppDelegate -// @synthesize window = _window; -@synthesize managedObjectContext = __managedObjectContext; -@synthesize managedObjectModel = __managedObjectModel; -@synthesize persistentStoreCoordinator = __persistentStoreCoordinator; +@synthesize managedObjectContext = _managedObjectContext; +@synthesize managedObjectModel = _managedObjectModel; +@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; #pragma mark - #pragma mark === UIApplicationDelegate Methods === @@ -47,35 +50,47 @@ @implementation UYLAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; + UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; + navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem; + splitViewController.delegate = self; + splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; - UIStoryboard *countryStoryboard = [UIStoryboard storyboardWithName:@"Country" bundle:nil]; - UINavigationController *navController = [countryStoryboard instantiateInitialViewController]; - UYLCountryTableViewController *countryViewController = (UYLCountryTableViewController *)navController.topViewController; - -// The following two lines are used to create the view controllers when not using storyboards -// UYLCountryTableViewController *countryViewController = [[UYLCountryTableViewController alloc] -// initWithNibName:@"UYLCountryTableViewController" -// bundle:nil]; -// UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:countryViewController]; + CGFloat minimumWidth = MIN(CGRectGetWidth(splitViewController.view.bounds),CGRectGetHeight(splitViewController.view.bounds)); + splitViewController.minimumPrimaryColumnWidth = minimumWidth / 2; + splitViewController.maximumPrimaryColumnWidth = minimumWidth; - countryViewController.managedObjectContext = self.managedObjectContext; - [Country importDataToMoc:self.managedObjectContext]; - - self.window.rootViewController = navController; - self.window.backgroundColor = [UIColor whiteColor]; - [self.window makeKeyAndVisible]; + UINavigationController *masterNavigationController = splitViewController.viewControllers[0]; + UYLCountryTableViewController *controller = (UYLCountryTableViewController *)masterNavigationController.topViewController; + controller.managedObjectContext = self.managedObjectContext; + return YES; } -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - [self saveContext]; -} +#pragma mark - +#pragma mark === UISplitViewControllerDelegate === +#pragma mark - -- (void)applicationWillTerminate:(UIApplication *)application +// When transitioning to a collapsed interface if our secondary view controller is the detail view +// controller navigation hierarchy and it does not have a country to display (which is the case on +// initial launch) we discard and show the master view controller. + +- (BOOL)splitViewController:(UISplitViewController *)splitViewController +collapseSecondaryViewController:(UIViewController *)secondaryViewController + ontoPrimaryViewController:(UIViewController *)primaryViewController { - [self saveContext]; + if ([secondaryViewController isKindOfClass:[UINavigationController class]] + && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[UYLCountryViewController class]] + && ([(UYLCountryViewController *)[(UINavigationController *)secondaryViewController topViewController] country] == nil)) + { + // Return YES to indicate that we have handled the collapse by doing nothing + // the secondary controller will be discarded. + return YES; + } + else + { + return NO; + } } #pragma mark - @@ -84,60 +99,62 @@ - (void)applicationWillTerminate:(UIApplication *)application - (NSManagedObjectContext *)managedObjectContext { - if (__managedObjectContext != nil) { - return __managedObjectContext; + if (_managedObjectContext != nil) + { + return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; - if (coordinator != nil) { - __managedObjectContext = [[NSManagedObjectContext alloc] init]; - [__managedObjectContext setPersistentStoreCoordinator:coordinator]; + if (coordinator != nil) + { + _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } - return __managedObjectContext; + return _managedObjectContext; } - (NSManagedObjectModel *)managedObjectModel { - if (__managedObjectModel != nil) { - return __managedObjectModel; + if (_managedObjectModel != nil) + { + return _managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"WorldFacts" withExtension:@"momd"]; - __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; - return __managedObjectModel; + _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + return _managedObjectModel; } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { - if (__persistentStoreCoordinator != nil) { - return __persistentStoreCoordinator; + if (_persistentStoreCoordinator != nil) + { + return _persistentStoreCoordinator; } - NSURL *storeURL = [[self applicationSupportDirectory] URLByAppendingPathComponent:@"WorldFacts.sqlite"]; + // Using the SQLite store generated by WorldFactsBuilder OS X and added to the + // application bundle. Make sure to open the store in read only mode since + // we cannot modify files in the bundle. + NSURL *storeURL = [[NSBundle mainBundle] URLForResource:@"WorldFacts" withExtension:@"sqlite"]; + NSDictionary *storeOptions = @{NSReadOnlyPersistentStoreOption: @YES}; NSError *error = nil; - __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; - if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { + _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; + if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType + configuration:nil + URL:storeURL + options:storeOptions + error:&error]) + { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); } - return __persistentStoreCoordinator; + return _persistentStoreCoordinator; } #pragma mark - #pragma mark === Utility Methods === #pragma mark - -- (void)saveContext -{ - NSError *error = nil; - NSManagedObjectContext *managedObjectContext = self.managedObjectContext; - if (managedObjectContext != nil) { - if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { - NSLog(@"Unresolved error %@, %@", error, [error userInfo]); - } - } -} - - (NSURL *)applicationSupportDirectory { NSError *error = nil; diff --git a/WorldFacts/WorldFacts/UYLCountryTableViewController.h b/WorldFacts/WorldFacts/UYLCountryTableViewController.h index 41bd1bc..3f6cfc2 100644 --- a/WorldFacts/WorldFacts/UYLCountryTableViewController.h +++ b/WorldFacts/WorldFacts/UYLCountryTableViewController.h @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2014 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -31,7 +31,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#import +@import UIKit; @interface UYLCountryTableViewController : UITableViewController diff --git a/WorldFacts/WorldFacts/UYLCountryTableViewController.m b/WorldFacts/WorldFacts/UYLCountryTableViewController.m index c074c4c..8d0b389 100644 --- a/WorldFacts/WorldFacts/UYLCountryTableViewController.m +++ b/WorldFacts/WorldFacts/UYLCountryTableViewController.m @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2015 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -33,37 +33,30 @@ #import "UYLCountryTableViewController.h" #import "UYLCountryViewController.h" +#import "CountryCell.h" #import "Country+Extensions.h" -@interface UYLCountryTableViewController () +@interface UYLCountryTableViewController () @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; @property (strong, nonatomic) NSNumberFormatter *decimalFormatter; @property (strong, nonatomic) NSArray *filteredList; @property (strong, nonatomic) NSFetchRequest *searchFetchRequest; +@property (strong, nonatomic) UISearchController *searchController; -@property (strong, nonatomic) IBOutlet UITableViewCell *countryCell; -@property (strong, nonatomic) UINib *countryCellNib; - -typedef enum +typedef NS_ENUM(NSInteger, UYLWorldFactsSearchScope) { searchScopeCountry = 0, searchScopeCapital = 1 - -} UYLWorldFactsSearchScope; +}; @end @implementation UYLCountryTableViewController -static NSString *UYLNibCountryCellIdentifier = @"UYLNibCountryCellIdentifier"; static NSString *UYLCountryCellIdentifier = @"UYLCountryCellIdentifier"; static NSString *UYLSegueShowCountry = @"UYLSegueShowCountry"; -#define UYL_COUNTRYCELLTAG_NAME 100 -#define UYL_COUNTRYCELLTAG_CAPITAL 200 -#define UYL_COUNTRYCELLTAG_POP 300 - #pragma mark - #pragma mark === View Life Cycle Management === #pragma mark - @@ -71,66 +64,81 @@ @implementation UYLCountryTableViewController - (void)viewDidLoad { [super viewDidLoad]; - self.title = NSLocalizedString(@"World", @"World"); + self.title = NSLocalizedString(@"WorldTableViewTitle", @"World"); - // When not using storyboards the following two lines load and register the NIB - // for the country cell. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification object:nil]; + self.tableView.estimatedRowHeight = 64.0; + self.tableView.rowHeight = UITableViewAutomaticDimension; + + // No search results controller to display the search results in the current view + self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; + self.searchController.searchResultsUpdater = self; + self.searchController.dimsBackgroundDuringPresentation = NO; + + // Configure the search bar with scope buttons and add it to the table view header + self.searchController.searchBar.scopeButtonTitles = @[NSLocalizedString(@"ScopeButtonCountry",@"Country"), + NSLocalizedString(@"ScopeButtonCapital",@"Capital")]; + self.searchController.searchBar.delegate = self; + + if (@available(iOS 11.0, *)) { + self.navigationItem.searchController = self.searchController; + self.navigationItem.hidesSearchBarWhenScrolling = NO; + } else { + self.tableView.tableHeaderView = self.searchController.searchBar; + } + self.definesPresentationContext = YES; + + // The search bar does not seem to set its size automatically + // which causes it to have zero height when there is no scope + // bar. If you remove the scopeButtonTitles above and the + // search bar is no longer visible make sure you force the + // search bar to size itself (make sure you do this after + // you add it to the view hierarchy). + [self.searchController.searchBar sizeToFit]; - // UINib *countryNib = [UINib nibWithNibName:@"CountryCell" bundle:nil]; - // [self.tableView registerNib:countryNib forCellReuseIdentifier:UYLCountryCellIdentifier]; + // Register for 3D Touch Previewing if available + if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && + (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) + { + [self registerForPreviewingWithDelegate:self sourceView:self.view]; + } +} + +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self.tableView reloadData]; } -- (void)viewDidUnload +- (void)didReceiveMemoryWarning { - [super viewDidUnload]; + [super didReceiveMemoryWarning]; self.decimalFormatter = nil; + self.searchFetchRequest = nil; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +- (void)dealloc { - return YES; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIContentSizeCategoryDidChangeNotification + object:nil]; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - NSLog(@"prepareForSeqgue: %@ - %@",segue.identifier, [sender reuseIdentifier]); if ([segue.identifier isEqualToString:UYLSegueShowCountry]) { - Country *country = nil; - if (self.searchDisplayController.isActive) - { - NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForCell:sender]; - country = [self.filteredList objectAtIndex:indexPath.row]; - } - else - { - NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; - country = [self.fetchedResultsController objectAtIndexPath:indexPath]; - } - UYLCountryViewController *viewController = segue.destinationViewController; - viewController.country = country; + NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; + Country *country = [self countryForIndexPath:indexPath]; + [self configureNavigationController:segue.destinationViewController withCountry:country]; } } -- (void)didReceiveMemoryWarning -{ - self.searchFetchRequest = nil; - [super didReceiveMemoryWarning]; -} - #pragma mark - #pragma mark === Accessors === #pragma mark - -- (UINib *)countryCellNib -{ - if (!_countryCellNib) - { - _countryCellNib = [UINib nibWithNibName:@"CountryCell" bundle:nil]; - } - return _countryCellNib; -} - - (NSNumberFormatter *)decimalFormatter { if (!_decimalFormatter) @@ -159,127 +167,108 @@ - (NSFetchRequest *)searchFetchRequest return _searchFetchRequest; } +#pragma mark - +#pragma mark === UIViewControllerPreviewingDelegate Methods === +#pragma mark - + +- (UIViewController *)previewingContext:(id)previewingContext + viewControllerForLocation:(CGPoint)location { + + NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location]; + Country *country = [self countryForIndexPath:indexPath]; + if (country) { + CountryCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; + if (cell) { + previewingContext.sourceRect = cell.frame; + UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"UYLCountryNavController"]; + [self configureNavigationController:navController withCountry:country]; + return navController; + } + } + return nil; +} + +- (void)previewingContext:(id)previewingContext commitViewController:(UIViewController *)viewControllerToCommit { + + [self showDetailViewController:viewControllerToCommit sender:self]; +} + #pragma mark - #pragma mark === UITableViewDataSource Delegate Methods === #pragma mark - - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - if (tableView == self.tableView) + if (self.searchController.active) { - return [[self.fetchedResultsController sections] count]; + return 1; } else { - return 1; + return [[self.fetchedResultsController sections] count]; } } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (tableView == self.tableView) + if (self.searchController.active) { - id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; - return [sectionInfo numberOfObjects]; + return [self.filteredList count]; } else { - return [self.filteredList count]; + id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; + return [sectionInfo numberOfObjects]; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - // Note that here we are not using the tableView parameter to retrieve a new table view cell. Instead - // we always use self.tableView. This is necessary as our custom table view cell defined in the - // storyboard and is not registered with the search results table view but only with the original - // table. - - UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:UYLCountryCellIdentifier]; - - // ******************************************************************************* - // If you are targetting iOS 5 there is a serious bug here with VoiceOver active!! - // ******************************************************************************* - - // A bug in iOS 5 causes the above call to not return with a new cell when VoiceOver is active. - // We therefore fallback to the old mechanism of manually loading the cell from the NIB file. - - // Unfortunately this has two side effects. Firstly we need to manually perform the segue - // when the row is selected. To ensure we only do that for the cells loaded manually we - // need to use a different reuseIdentifer. + CountryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:UYLCountryCellIdentifier forIndexPath:indexPath]; - // More seriously since the reuse mechanism does not work when VoiceOver is active - // new cells are allocated each time the table is reloaded or scrolled and never reused. - - if (cell == nil) - { - // The following call should return cells for reuse but when VoiceOver is active - // it always returns nil - - cell = [self.tableView dequeueReusableCellWithIdentifier:UYLNibCountryCellIdentifier]; - - if (cell == nil) - { - [self.countryCellNib instantiateWithOwner:self options:nil]; - cell = self.countryCell; - self.countryCell = nil; - } - } - Country *country = nil; - if (tableView == self.tableView) + if (self.searchController.active) { - country = [self.fetchedResultsController objectAtIndexPath:indexPath]; + country = [self.filteredList objectAtIndex:indexPath.row]; } else { - country = [self.filteredList objectAtIndex:indexPath.row]; + country = [self.fetchedResultsController objectAtIndexPath:indexPath]; } - UILabel *nameLabel = (UILabel *)[cell viewWithTag:UYL_COUNTRYCELLTAG_NAME]; - nameLabel.text = country.name; - - UILabel *capLabel = (UILabel *)[cell viewWithTag:UYL_COUNTRYCELLTAG_CAPITAL]; - capLabel.text = country.capital; - - UILabel *popLabel = (UILabel *)[cell viewWithTag:UYL_COUNTRYCELLTAG_POP]; - NSString *population = [self.decimalFormatter stringFromNumber:country.population]; - popLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Pop: %@", @"Pop:"), population]; + cell.name = country.name; + cell.capital = country.capital; + NSString *population = [self.decimalFormatter stringFromNumber:country.population]; + cell.population = [NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"PopulationShortLabel", @"Pop:"), population]; return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { - if (tableView == self.tableView) + if (!self.searchController.active) { id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo name]; } - else - { - return nil; - } + return nil; } - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { - if (tableView == self.tableView) + if (!self.searchController.active) { NSMutableArray *index = [NSMutableArray arrayWithObject:UITableViewIndexSearch]; NSArray *initials = [self.fetchedResultsController sectionIndexTitles]; [index addObjectsFromArray:initials]; return index; } - else - { - return nil; - } + return nil; } - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { - if (tableView == self.tableView) + if (!self.searchController.active) { if (index > 0) { @@ -293,31 +282,12 @@ - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSS // The first entry in the index is for the search icon so we return section not found // and force the table to scroll to the top. - self.tableView.contentOffset = CGPointZero; + CGRect searchBarFrame = self.searchController.searchBar.frame; + [self.tableView scrollRectToVisible:searchBarFrame animated:NO]; return NSNotFound; } } - else - { - return 0; - } -} - -#pragma mark - -#pragma mark === UITableViewDelegate === -#pragma mark - - -// The following method is implemented as a workaround for the iOS 5 bug when dequeuing -// cells with VoiceOver active. When the cell is not loaded from the storyboard -// we need to manually perform the segue. - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; - if ([cell.reuseIdentifier isEqualToString:UYLNibCountryCellIdentifier]) - { - [self performSegueWithIdentifier:UYLSegueShowCountry sender:cell]; - } + return 0; } #pragma mark - @@ -331,26 +301,29 @@ - (NSFetchedResultsController *)fetchedResultsController return _fetchedResultsController; } - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; - NSEntityDescription *entity = [NSEntityDescription entityForName:@"Country" inManagedObjectContext:self.managedObjectContext]; - [fetchRequest setEntity:entity]; - - NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; - NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; - [fetchRequest setSortDescriptors:sortDescriptors]; - - NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest - managedObjectContext:self.managedObjectContext - sectionNameKeyPath:@"sectionTitle" - cacheName:@"Country"]; - frc.delegate = self; - self.fetchedResultsController = frc; - - NSError *error = nil; - if (![self.fetchedResultsController performFetch:&error]) + if (self.managedObjectContext) { - NSLog(@"Unresolved error %@, %@", error, [error userInfo]); - } + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; + NSEntityDescription *entity = [NSEntityDescription entityForName:@"Country" inManagedObjectContext:self.managedObjectContext]; + [fetchRequest setEntity:entity]; + + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; + NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; + [fetchRequest setSortDescriptors:sortDescriptors]; + + NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest + managedObjectContext:self.managedObjectContext + sectionNameKeyPath:@"sectionTitle" + cacheName:@"Country"]; + frc.delegate = self; + self.fetchedResultsController = frc; + + NSError *error = nil; + if (![self.fetchedResultsController performFetch:&error]) + { + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + } + } return _fetchedResultsController; } @@ -361,26 +334,23 @@ - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller } #pragma mark - -#pragma mark === UISearchDisplayDelegate === +#pragma mark === UISearchBarDelegate === #pragma mark - -- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString +- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope { - UYLWorldFactsSearchScope scopeKey = controller.searchBar.selectedScopeButtonIndex; - [self searchForText:searchString scope:scopeKey]; - return YES; + [self updateSearchResultsForSearchController:self.searchController]; } -- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption -{ - NSString *searchString = controller.searchBar.text; - [self searchForText:searchString scope:searchOption]; - return YES; -} +#pragma mark - +#pragma mark === UISearchResultsUpdating === +#pragma mark - -- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView +- (void)updateSearchResultsForSearchController:(UISearchController *)searchController { - tableView.rowHeight = 64; + NSString *searchString = searchController.searchBar.text; + [self searchForText:searchString scope:searchController.searchBar.selectedScopeButtonIndex]; + [self.tableView reloadData]; } - (void)searchForText:(NSString *)searchText scope:(UYLWorldFactsSearchScope)scopeOption @@ -407,4 +377,31 @@ - (void)searchForText:(NSString *)searchText scope:(UYLWorldFactsSearchScope)sco } } +#pragma mark - +#pragma mark === Helper methods === +#pragma mark - + +- (Country *)countryForIndexPath:(NSIndexPath *)indexPath { + + Country *country = nil; + if (indexPath) { + if (self.searchController.isActive) { + country = [self.filteredList objectAtIndex:indexPath.row]; + } else { + country = [self.fetchedResultsController objectAtIndexPath:indexPath]; + } + } + return country; +} + +- (void)configureNavigationController:(UINavigationController *)navController withCountry:(Country *)country { + + if ([navController.topViewController isKindOfClass:[UYLCountryViewController class]]) { + UYLCountryViewController *controller = (UYLCountryViewController *)navController.topViewController; + controller.country = country; + controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem; + controller.navigationItem.leftItemsSupplementBackButton = YES; + } +} + @end diff --git a/WorldFacts/WorldFacts/UYLCountryTableViewController.xib b/WorldFacts/WorldFacts/UYLCountryTableViewController.xib deleted file mode 100644 index 0f4839a..0000000 --- a/WorldFacts/WorldFacts/UYLCountryTableViewController.xib +++ /dev/null @@ -1,158 +0,0 @@ - - - - 1296 - 11E53 - 2182 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - {{0, 44}, {320, 436}} - - - - _NS:9 - - 3 - MQA - - YES - - NO - - IBCocoaTouchFramework - YES - 1 - 0 - YES - 64 - 22 - 22 - - - - - - - view - - - - 5 - - - - dataSource - - - - 3 - - - - delegate - - - - 4 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - UYLCountryTableViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 5 - - - - - UYLCountryTableViewController - UITableViewController - - countryCell - UITableViewCell - - - countryCell - - countryCell - UITableViewCell - - - - IBProjectSource - ./Classes/UYLCountryTableViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - diff --git a/WorldFacts/WorldFacts/UYLCountryViewController.h b/WorldFacts/WorldFacts/UYLCountryViewController.h index f4f198d..e7dda9c 100644 --- a/WorldFacts/WorldFacts/UYLCountryViewController.h +++ b/WorldFacts/WorldFacts/UYLCountryViewController.h @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2014 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -31,7 +31,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#import +@import UIKit; #import "Country.h" @interface UYLCountryViewController : UIViewController diff --git a/WorldFacts/WorldFacts/UYLCountryViewController.m b/WorldFacts/WorldFacts/UYLCountryViewController.m index 0a2afe5..f484fdc 100644 --- a/WorldFacts/WorldFacts/UYLCountryViewController.m +++ b/WorldFacts/WorldFacts/UYLCountryViewController.m @@ -3,7 +3,7 @@ // WorldFacts // // Created by Keith Harrison http://useyourloaf.com -// Copyright (c) 2012 Keith Harrison. All rights reserved. +// Copyright (c) 2012-2014 Keith Harrison. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: @@ -43,18 +43,48 @@ @interface UYLCountryViewController () @property (nonatomic, weak) IBOutlet UILabel *population; @property (nonatomic, weak) IBOutlet UILabel *tld; +@property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *headlineCollection; +@property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *bodyCollection; + @end @implementation UYLCountryViewController -//@synthesize country=_country; -//@synthesize area=_area; -//@synthesize capital=_capital; -//@synthesize continent=_continent; -//@synthesize currency=_currency; -//@synthesize phone=_phone; -//@synthesize population=_population; -//@synthesize tld=_tld; +- (void)setCountry:(Country *)newCountry +{ + if (_country != newCountry) + { + _country = newCountry; + [self configureView]; + } +} + +- (void)configureView +{ + for (UILabel *label in self.headlineCollection) + { + label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + } + + for (UILabel *label in self.bodyCollection) + { + label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + } + + self.title = self.country.name; + + NSString *area = [NSNumberFormatter localizedStringFromNumber:self.country.area numberStyle:NSNumberFormatterDecimalStyle]; + self.area.text = [area length] ? area : @"None"; + + NSString *population = [NSNumberFormatter localizedStringFromNumber:self.country.population numberStyle:NSNumberFormatterDecimalStyle]; + self.population.text = [population length] ? population: @"None"; + + self.capital.text = [self.country.capital length] ? self.country.capital : @"None"; + self.continent.text = [self.country.continent length] ? self.country.continent : @"None"; + self.currency.text = [self.country.currency length] ? self.country.currency : @"None"; + self.phone.text = [self.country.phone length] ? self.country.phone : @"None"; + self.tld.text = [self.country.tld length] ? self.country.tld : @"None"; +} #pragma mark - #pragma mark === View Life Cycle Management === @@ -63,21 +93,23 @@ @implementation UYLCountryViewController - (void)viewDidLoad { [super viewDidLoad]; + [self configureView]; - self.title = self.country.name; - self.area.text = [NSNumberFormatter localizedStringFromNumber:self.country.area numberStyle:NSNumberFormatterDecimalStyle]; - self.population.text = [NSNumberFormatter localizedStringFromNumber:self.country.population numberStyle:NSNumberFormatterDecimalStyle]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangePreferredContentSize:) + name:UIContentSizeCategoryDidChangeNotification object:nil]; +} - self.capital.text = self.country.capital; - self.continent.text = self.country.continent; - self.currency.text = self.country.currency; - self.phone.text = self.country.phone; - self.tld.text = self.country.tld; +- (void)didChangePreferredContentSize:(NSNotification *)notification +{ + [self configureView]; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +- (void)dealloc { - return YES; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIContentSizeCategoryDidChangeNotification + object:nil]; } @end diff --git a/WorldFacts/WorldFacts/UYLCountryViewController.xib b/WorldFacts/WorldFacts/UYLCountryViewController.xib deleted file mode 100644 index 20f908c..0000000 --- a/WorldFacts/WorldFacts/UYLCountryViewController.xib +++ /dev/null @@ -1,678 +0,0 @@ - - - - 1296 - 11E53 - 2182 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUIView - IBUILabel - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 294 - {{20, 20}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Capital - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - 2 - 17 - - - Helvetica-Bold - 17 - 16 - - - - - 294 - {{20, 49}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Population - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 294 - {{20, 78}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Area - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 294 - {{20, 107}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Currency - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 294 - {{20, 136}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Continent - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 294 - {{20, 165}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - Phone - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 294 - {{20, 194}, {88, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - TLD - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - 2 - - - - - - 291 - {{122, 20}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - capital - - - 0 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - - 291 - {{122, 49}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - population - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - - 291 - {{122, 78}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - area - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - - 291 - {{122, 107}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - currency - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - - 291 - {{122, 136}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - continent - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - - 291 - {{122, 165}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - phone - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - - 291 - {{122, 194}, {178, 21}} - - - - _NS:9 - NO - YES - 7 - NO - IBCocoaTouchFramework - tld - - 1 - MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA - - - 0 - 10 - - - - - {{0, 64}, {320, 416}} - - - - - 3 - MQA - - 2 - - - - - NO - - IBCocoaTouchFramework - - - - - - - area - - - - 17 - - - - capital - - - - 18 - - - - continent - - - - 19 - - - - currency - - - - 20 - - - - phone - - - - 21 - - - - population - - - - 22 - - - - tld - - - - 23 - - - - view - - - - 24 - - - - - - 0 - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 3 - - - - - 4 - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - 10 - - - - - 11 - - - - - 12 - - - - - 13 - - - - - 14 - - - - - 15 - - - - - 16 - - - - - - - UYLCountryViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 24 - - - - - UYLCountryViewController - UIViewController - - UILabel - UILabel - UILabel - UILabel - UILabel - UILabel - UILabel - - - - area - UILabel - - - capital - UILabel - - - continent - UILabel - - - currency - UILabel - - - phone - UILabel - - - population - UILabel - - - tld - UILabel - - - - IBProjectSource - ./Classes/UYLCountryViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - diff --git a/WorldFacts/WorldFacts/WorldFacts-Info.plist b/WorldFacts/WorldFacts/WorldFacts-Info.plist index f630c4e..528a05a 100644 --- a/WorldFacts/WorldFacts/WorldFacts-Info.plist +++ b/WorldFacts/WorldFacts/WorldFacts-Info.plist @@ -8,21 +8,8 @@ ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} - CFBundleIcons - - CFBundlePrimaryIcon - - CFBundleIconFiles - - Icon.png - Icon@2x.png - Icon-Small.png - Icon-Small@2x.png - - - CFBundleIdentifier - com.useyourloaf.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -30,17 +17,17 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion - 1.0 + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS - UIRequiredDeviceCapabilities - - armv7 - + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/WorldFacts/WorldFacts/WorldFacts-Prefix.pch b/WorldFacts/WorldFacts/WorldFacts-Prefix.pch deleted file mode 100644 index e128607..0000000 --- a/WorldFacts/WorldFacts/WorldFacts-Prefix.pch +++ /dev/null @@ -1,15 +0,0 @@ -// -// Prefix header for all source files of the 'WorldFacts' target in the 'WorldFacts' project -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iOS SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import - #import -#endif diff --git a/WorldFacts/WorldFacts/WorldFacts.sqlite b/WorldFacts/WorldFacts/WorldFacts.sqlite new file mode 100644 index 0000000..e339fd7 Binary files /dev/null and b/WorldFacts/WorldFacts/WorldFacts.sqlite differ diff --git a/WorldFacts/WorldFacts/en.lproj/Localizable.strings b/WorldFacts/WorldFacts/en.lproj/Localizable.strings new file mode 100644 index 0000000..5c46c48 --- /dev/null +++ b/WorldFacts/WorldFacts/en.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* + Localizable.strings + WorldFacts +*/ + +"WorldTableViewTitle" = "World"; +"ScopeButtonCountry" = "Country"; +"ScopeButtonCapital" = "Capital"; +"PopulationShortLabel" = "Pop:"; \ No newline at end of file diff --git a/WorldFacts/WorldFactsBuilder/AppDelegate.h b/WorldFacts/WorldFactsBuilder/AppDelegate.h new file mode 100644 index 0000000..5999579 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/AppDelegate.h @@ -0,0 +1,45 @@ +// +// AppDelegate.h +// WorldFactsBuilder +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface AppDelegate : NSObject + +@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; +@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; +@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; + + +@end + diff --git a/WorldFacts/WorldFactsBuilder/AppDelegate.m b/WorldFacts/WorldFactsBuilder/AppDelegate.m new file mode 100644 index 0000000..5af93ae --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/AppDelegate.m @@ -0,0 +1,202 @@ +// +// AppDelegate.m +// WorldFactsBuilder +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "AppDelegate.h" + +@interface AppDelegate () + +- (IBAction)saveAction:(id)sender; + +@end + +@implementation AppDelegate + +#pragma mark - +#pragma mark === Core Data Stack === +#pragma mark - + +@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; +@synthesize managedObjectModel = _managedObjectModel; +@synthesize managedObjectContext = _managedObjectContext; + +- (NSURL *)applicationDocumentsDirectory { + NSURL *appSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject]; + return [appSupportURL URLByAppendingPathComponent:@"com.useyourloaf.WorldFactsBuilder"]; +} + +- (NSManagedObjectModel *)managedObjectModel { + if (_managedObjectModel) { + return _managedObjectModel; + } + + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"WorldFacts" withExtension:@"momd"]; + _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + return _managedObjectModel; +} + +- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { + if (_persistentStoreCoordinator) { + return _persistentStoreCoordinator; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *applicationDocumentsDirectory = [self applicationDocumentsDirectory]; + BOOL shouldFail = NO; + NSError *error = nil; + NSString *failureReason = @"There was an error creating or loading the application's saved data."; + + // Make sure the application files directory is there + NSDictionary *properties = [applicationDocumentsDirectory resourceValuesForKeys:@[NSURLIsDirectoryKey] error:&error]; + if (properties) { + if (![properties[NSURLIsDirectoryKey] boolValue]) { + failureReason = [NSString stringWithFormat:@"Expected a folder to store application data, found a file (%@).", [applicationDocumentsDirectory path]]; + shouldFail = YES; + } + } else if ([error code] == NSFileReadNoSuchFileError) { + error = nil; + [fileManager createDirectoryAtPath:[applicationDocumentsDirectory path] withIntermediateDirectories:YES attributes:nil error:&error]; + } + + if (!shouldFail && !error) { + NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; + + // To make it easy to copy the store to the iOS target disable the Write Ahead Logging + // journalling. + NSURL *url = [applicationDocumentsDirectory URLByAppendingPathComponent:@"WorldFacts.sqlite"]; + NSDictionary *options = @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}}; + if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType + configuration:nil + URL:url + options:options + error:&error]) { + coordinator = nil; + } + _persistentStoreCoordinator = coordinator; + } + + if (shouldFail || error) { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data"; + dict[NSLocalizedFailureReasonErrorKey] = failureReason; + if (error) { + dict[NSUnderlyingErrorKey] = error; + } + error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict]; + [[NSApplication sharedApplication] presentError:error]; + } + return _persistentStoreCoordinator; +} + +- (NSManagedObjectContext *)managedObjectContext { + if (_managedObjectContext) { + return _managedObjectContext; + } + + NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; + if (!coordinator) { + return nil; + } + _managedObjectContext = [[NSManagedObjectContext alloc] init]; + [_managedObjectContext setPersistentStoreCoordinator:coordinator]; + + return _managedObjectContext; +} + +#pragma mark - +#pragma mark === Core Data Saving and Undo Support === +#pragma mark - + +- (IBAction)saveAction:(id)sender { + // Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user. + if (![[self managedObjectContext] commitEditing]) { + NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd)); + } + + NSError *error = nil; + if ([[self managedObjectContext] hasChanges] && ![[self managedObjectContext] save:&error]) { + [[NSApplication sharedApplication] presentError:error]; + } +} + +- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { + // Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application. + return [[self managedObjectContext] undoManager]; +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { + // Save changes in the application's managed object context before the application terminates. + + if (!_managedObjectContext) { + return NSTerminateNow; + } + + if (![[self managedObjectContext] commitEditing]) { + NSLog(@"%@:%@ unable to commit editing to terminate", [self class], NSStringFromSelector(_cmd)); + return NSTerminateCancel; + } + + if (![[self managedObjectContext] hasChanges]) { + return NSTerminateNow; + } + + NSError *error = nil; + if (![[self managedObjectContext] save:&error]) { + + // Customize this code block to include application-specific recovery steps. + BOOL result = [sender presentError:error]; + if (result) { + return NSTerminateCancel; + } + + NSString *question = NSLocalizedString(@"Could not save changes while quitting. Quit anyway?", @"Quit without saves error question message"); + NSString *info = NSLocalizedString(@"Quitting now will lose any changes you have made since the last successful save", @"Quit without saves error question info"); + NSString *quitButton = NSLocalizedString(@"Quit anyway", @"Quit anyway button title"); + NSString *cancelButton = NSLocalizedString(@"Cancel", @"Cancel button title"); + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:question]; + [alert setInformativeText:info]; + [alert addButtonWithTitle:quitButton]; + [alert addButtonWithTitle:cancelButton]; + + NSInteger answer = [alert runModal]; + + if (answer == NSAlertFirstButtonReturn) { + return NSTerminateCancel; + } + } + + return NSTerminateNow; +} + +@end diff --git a/WorldFacts/WorldFactsBuilder/Base.lproj/Main.storyboard b/WorldFacts/WorldFactsBuilder/Base.lproj/Main.storyboard new file mode 100644 index 0000000..ee11e26 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/Base.lproj/Main.storyboard @@ -0,0 +1,858 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WorldFacts/WorldFactsBuilder/CountryTableViewController.h b/WorldFacts/WorldFactsBuilder/CountryTableViewController.h new file mode 100644 index 0000000..1b2c7a3 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/CountryTableViewController.h @@ -0,0 +1,39 @@ +// +// CountryTableViewController.h +// WorldFacts +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface CountryTableViewController : NSViewController +@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext; +@end diff --git a/WorldFacts/WorldFactsBuilder/CountryTableViewController.m b/WorldFacts/WorldFactsBuilder/CountryTableViewController.m new file mode 100644 index 0000000..4fc2a0b --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/CountryTableViewController.m @@ -0,0 +1,55 @@ +// +// CountryTableViewController.m +// WorldFacts +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "CountryTableViewController.h" + +@interface CountryTableViewController () +@property (nonatomic, strong, readonly) NSArray *sortDescriptors; +@end + +@implementation CountryTableViewController + +@synthesize sortDescriptors = _sortDescriptors; + +- (NSArray *)sortDescriptors { + + if (_sortDescriptors == nil){ + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; + _sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; + } + return _sortDescriptors; +} + + +@end diff --git a/WorldFacts/WorldFactsBuilder/CountryWindowController.h b/WorldFacts/WorldFactsBuilder/CountryWindowController.h new file mode 100644 index 0000000..0a42510 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/CountryWindowController.h @@ -0,0 +1,41 @@ +// +// CountryWindowController.h +// WorldFacts +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +@interface CountryWindowController : NSWindowController + +@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext; + +@end diff --git a/WorldFacts/WorldFactsBuilder/CountryWindowController.m b/WorldFacts/WorldFactsBuilder/CountryWindowController.m new file mode 100644 index 0000000..d54b973 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/CountryWindowController.m @@ -0,0 +1,60 @@ +// +// CountryWindowController.m +// WorldFacts +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import "CountryWindowController.h" +#import "CountryTableViewController.h" +#import "AppDelegate.h" +#import "Country+Extensions.h" + +@implementation CountryWindowController + +- (void)windowWillLoad { + [super windowWillLoad]; + AppDelegate *delegate = [[NSApplication sharedApplication] delegate]; + self.managedObjectContext = delegate.managedObjectContext; + [Country importDataToMoc:self.managedObjectContext]; +} + +- (void)windowDidLoad { + [super windowDidLoad]; + CountryTableViewController *countryTVC = (CountryTableViewController *)self.contentViewController; + countryTVC.managedObjectContext = self.managedObjectContext; +} + +- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { + return self.managedObjectContext.undoManager; +} + + +@end diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/Contents.json b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..0a5a4d3 --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "WorldFacts16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "WorldFacts32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "WorldFacts32-1.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "WorldFacts64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "WorldFacts128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "WorldFacts256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "WorldFacts256-1.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "WorldFacts512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "WorldFacts512-1.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "WorldFacts1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts1024.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts1024.png new file mode 100644 index 0000000..21c54d3 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts1024.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts128.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts128.png new file mode 100644 index 0000000..0bf53c8 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts128.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts16.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts16.png new file mode 100644 index 0000000..ef703e5 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts16.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256-1.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256-1.png new file mode 100644 index 0000000..fa4a51c Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256-1.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256.png new file mode 100644 index 0000000..fa4a51c Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts256.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32-1.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32-1.png new file mode 100644 index 0000000..3f4208b Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32-1.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32.png new file mode 100644 index 0000000..3f4208b Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts32.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512-1.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512-1.png new file mode 100644 index 0000000..4ac8003 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512-1.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512.png new file mode 100644 index 0000000..4ac8003 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts512.png differ diff --git a/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts64.png b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts64.png new file mode 100644 index 0000000..3545630 Binary files /dev/null and b/WorldFacts/WorldFactsBuilder/Images.xcassets/AppIcon.appiconset/WorldFacts64.png differ diff --git a/WorldFacts/WorldFactsBuilder/Info.plist b/WorldFacts/WorldFactsBuilder/Info.plist new file mode 100644 index 0000000..cb0cc0d --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/WorldFacts/WorldFactsBuilder/main.m b/WorldFacts/WorldFactsBuilder/main.m new file mode 100644 index 0000000..fc0ab3e --- /dev/null +++ b/WorldFacts/WorldFactsBuilder/main.m @@ -0,0 +1,39 @@ +// +// main.m +// WorldFactsBuilder +// +// Created by Keith Harrison http://useyourloaf.com +// Copyright (c) 2015 Keith Harrison. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +}