diff --git a/FloatRatingView.podspec b/FloatRatingView.podspec index 3372809..889c15a 100644 --- a/FloatRatingView.podspec +++ b/FloatRatingView.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |spec| spec.social_media_url = 'https://twitter.com/glenyi' spec.source = { :git => 'https://github.com/glenyi/FloatRatingView.git', :tag => "#{spec.version}" } spec.source_files = 'FloatRatingView.swift' - spec.platform = :ios, '8.0' + spec.platforms = { :ios => '8.0', :tvos => '11.0' } spec.requires_arc = true spec.swift_version = '5.0' end diff --git a/Package.swift b/Package.swift index 26ff699..89ebd30 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ let package = Package( name: "FloatRatingView", defaultLocalization: "en", platforms: [ - .iOS(.v11) + .iOS(.v11), .tvOS(.v11), ], products: [ .library( diff --git a/Rating Demo/Rating Demo.xcodeproj/project.pbxproj b/Rating Demo/Rating Demo.xcodeproj/project.pbxproj index 55d8e93..a544647 100644 --- a/Rating Demo/Rating Demo.xcodeproj/project.pbxproj +++ b/Rating Demo/Rating Demo.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ B275F40719BA5E3600E6F169 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B275F40619BA5E3600E6F169 /* AppDelegate.swift */; }; B275F40919BA5E3600E6F169 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B275F40819BA5E3600E6F169 /* ViewController.swift */; }; - B275F40C19BA5E3600E6F169 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B275F40A19BA5E3600E6F169 /* Main.storyboard */; }; B275F40E19BA5E3600E6F169 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B275F40D19BA5E3600E6F169 /* Images.xcassets */; }; B275F42519BA5E5100E6F169 /* FloatRatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B275F42419BA5E5100E6F169 /* FloatRatingView.swift */; }; /* End PBXBuildFile section */ @@ -19,7 +18,6 @@ B275F40519BA5E3600E6F169 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B275F40619BA5E3600E6F169 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; B275F40819BA5E3600E6F169 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - B275F40B19BA5E3600E6F169 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; B275F40D19BA5E3600E6F169 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; B275F42419BA5E5100E6F169 /* FloatRatingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FloatRatingView.swift; path = ../../FloatRatingView.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -57,7 +55,6 @@ B275F42319BA5E3E00E6F169 /* FloatRatingView */, B275F40619BA5E3600E6F169 /* AppDelegate.swift */, B275F40819BA5E3600E6F169 /* ViewController.swift */, - B275F40A19BA5E3600E6F169 /* Main.storyboard */, B275F40D19BA5E3600E6F169 /* Images.xcassets */, B275F40419BA5E3600E6F169 /* Supporting Files */, ); @@ -108,7 +105,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 1030; + LastUpgradeCheck = 1400; ORGANIZATIONNAME = "On The Pursuit"; TargetAttributes = { B275F40019BA5E3600E6F169 = { @@ -119,10 +116,9 @@ }; buildConfigurationList = B275F3FC19BA5E3600E6F169 /* Build configuration list for PBXProject "Rating Demo" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); @@ -141,7 +137,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - B275F40C19BA5E3600E6F169 /* Main.storyboard in Resources */, B275F40E19BA5E3600E6F169 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -161,17 +156,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - B275F40A19BA5E3600E6F169 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - B275F40B19BA5E3600E6F169 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ B275F41B19BA5E3600E6F169 /* Debug */ = { isa = XCBuildConfiguration; @@ -196,6 +180,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -220,7 +205,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -251,6 +236,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -268,7 +254,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -282,11 +268,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = "Rating Demo/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.onthepursuit.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,3"; }; name = Debug; }; @@ -296,11 +286,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = "Rating Demo/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.onthepursuit.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,3"; }; name = Release; }; diff --git a/Rating Demo/Rating Demo.xcodeproj/xcshareddata/xcschemes/Rating Demo.xcscheme b/Rating Demo/Rating Demo.xcodeproj/xcshareddata/xcschemes/Rating Demo.xcscheme index 9b8108b..6b2c39a 100644 --- a/Rating Demo/Rating Demo.xcodeproj/xcshareddata/xcschemes/Rating Demo.xcscheme +++ b/Rating Demo/Rating Demo.xcodeproj/xcshareddata/xcschemes/Rating Demo.xcscheme @@ -1,6 +1,6 @@ - - - - + + - - Bool { - // Override point for customization after application launch. + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: LaunchOptions) -> Bool { + self.window = UIWindow(frame: UIScreen.main.bounds) + self.window?.rootViewController = UINavigationController(rootViewController: ViewController()) + self.window?.makeKeyAndVisible() + return true } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - } diff --git a/Rating Demo/Rating Demo/Base.lproj/Main.storyboard b/Rating Demo/Rating Demo/Base.lproj/Main.storyboard deleted file mode 100644 index 0ba17f0..0000000 --- a/Rating Demo/Rating Demo/Base.lproj/Main.storyboard +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Rating Demo/Rating Demo/Images.xcassets/AppIcon.appiconset/Contents.json b/Rating Demo/Rating Demo/Images.xcassets/AppIcon.appiconset/Contents.json index a396706..b6f1927 100644 --- a/Rating Demo/Rating Demo/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Rating Demo/Rating Demo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -2,18 +2,48 @@ "images" : [ { "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" + "scale" : "3x", + "size" : "20x20" }, { "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { diff --git a/Rating Demo/Rating Demo/Images.xcassets/StarEmpty.imageset/Contents.json b/Rating Demo/Rating Demo/Images.xcassets/StarEmpty.imageset/Contents.json index f2d2126..6e05745 100644 --- a/Rating Demo/Rating Demo/Images.xcassets/StarEmpty.imageset/Contents.json +++ b/Rating Demo/Rating Demo/Images.xcassets/StarEmpty.imageset/Contents.json @@ -5,9 +5,13 @@ "scale" : "1x" }, { + "filename" : "StarEmpty@2x.png", "idiom" : "universal", - "scale" : "2x", - "filename" : "StarEmpty@2x.png" + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" } ], "info" : { diff --git a/Rating Demo/Rating Demo/Images.xcassets/StarFull.imageset/Contents.json b/Rating Demo/Rating Demo/Images.xcassets/StarFull.imageset/Contents.json index 402adbb..ffdb7e6 100644 --- a/Rating Demo/Rating Demo/Images.xcassets/StarFull.imageset/Contents.json +++ b/Rating Demo/Rating Demo/Images.xcassets/StarFull.imageset/Contents.json @@ -5,9 +5,13 @@ "scale" : "1x" }, { + "filename" : "StarFull@2x.png", "idiom" : "universal", - "scale" : "2x", - "filename" : "StarFull@2x.png" + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" } ], "info" : { diff --git a/Rating Demo/Rating Demo/Info.plist b/Rating Demo/Rating Demo/Info.plist index 98813b6..858b848 100644 --- a/Rating Demo/Rating Demo/Info.plist +++ b/Rating Demo/Rating Demo/Info.plist @@ -24,12 +24,6 @@ UILaunchStoryboardName Main - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/Rating Demo/Rating Demo/ViewController.swift b/Rating Demo/Rating Demo/ViewController.swift index 34d4506..4eaeffd 100644 --- a/Rating Demo/Rating Demo/ViewController.swift +++ b/Rating Demo/Rating Demo/ViewController.swift @@ -10,19 +10,69 @@ import UIKit class ViewController: UIViewController { - @IBOutlet var ratingSegmentedControl: UISegmentedControl! - @IBOutlet var floatRatingView: FloatRatingView! - @IBOutlet var liveLabel: UILabel! - @IBOutlet var updatedLabel: UILabel! + private let segmentItems = ["Whole", "Half", "Float"] + private lazy var ratingSegmentedControl: UISegmentedControl = .init(items: self.segmentItems) + private lazy var floatRatingView: FloatRatingView = .init() + private lazy var liveLabel: UILabel = .init() + private lazy var updatedLabel: UILabel = .init() + + override func loadView() { + super.loadView() + + #if os(iOS) + self.view.backgroundColor = .systemBackground + #endif + + for v in [ratingSegmentedControl, floatRatingView, liveLabel, updatedLabel] { + v.translatesAutoresizingMaskIntoConstraints = false + self.view.addSubview(v) + } + + self.ratingSegmentedControl.addTarget(self, action: #selector(ratingTypeChanged(_:)), for: .valueChanged) + + self.floatRatingView.emptyImage = #imageLiteral(resourceName: "StarEmpty") + self.floatRatingView.fullImage = #imageLiteral(resourceName: "StarFull") + self.floatRatingView.minRating = 1 + self.floatRatingView.maxRating = 5 + self.floatRatingView.rating = 2.5 + self.floatRatingView.minImageSize = .init(width: 44, height: 44) + + // Auto Layout // + + let widthConstraint = ratingSegmentedControl.widthAnchor + #if os(tvOS) + .constraint(equalTo: view.widthAnchor, multiplier: 0.333) + #else + .constraint(equalTo: view.widthAnchor, constant: -100) + #endif + + NSLayoutConstraint.activate([ + ratingSegmentedControl.topAnchor.constraint(equalTo: view.topAnchor, constant: 200), + ratingSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor), + widthConstraint, + + floatRatingView.topAnchor.constraint(equalTo: ratingSegmentedControl.bottomAnchor, constant: 20), + floatRatingView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + floatRatingView.heightAnchor.constraint(equalToConstant: 44), + floatRatingView.widthAnchor.constraint(equalTo: ratingSegmentedControl.widthAnchor), + + liveLabel.topAnchor.constraint(equalTo: floatRatingView.bottomAnchor, constant: 50), + liveLabel.leadingAnchor.constraint(equalTo: ratingSegmentedControl.leadingAnchor), + updatedLabel.topAnchor.constraint(equalTo: liveLabel.bottomAnchor, constant: 10), + updatedLabel.leadingAnchor.constraint(equalTo: ratingSegmentedControl.leadingAnchor) + ]) + } override func viewDidLoad() { super.viewDidLoad() + + self.title = "Float Rating View" // Reset float rating view's background color floatRatingView.backgroundColor = UIColor.clear - /** Note: With the exception of contentMode, type and delegate, - all properties can be set directly in Interface Builder **/ + // Note: With the exception of contentMode, type and delegate, + // all properties can be set directly in Interface Builder floatRatingView.delegate = self floatRatingView.contentMode = UIView.ContentMode.scaleAspectFit floatRatingView.type = .halfRatings @@ -31,35 +81,24 @@ class ViewController: UIViewController { ratingSegmentedControl.selectedSegmentIndex = 1 // Labels init - liveLabel.text = String(format: "%.2f", self.floatRatingView.rating) - updatedLabel.text = String(format: "%.2f", self.floatRatingView.rating) + self.floatRatingView(self.floatRatingView, isUpdating: 0) + self.floatRatingView(self.floatRatingView, didUpdate: 0) } - @IBAction func ratingTypeChanged(_ sender: UISegmentedControl) { - switch sender.selectedSegmentIndex { - case 0: - floatRatingView.type = .wholeRatings - case 1: - floatRatingView.type = .halfRatings - case 2: - floatRatingView.type = .floatRatings - default: - floatRatingView.type = .wholeRatings - } + @objc func ratingTypeChanged(_ sender: UISegmentedControl) { + self.floatRatingView.type = .init(rawValue: sender.selectedSegmentIndex) ?? .wholeRatings } } -extension ViewController: FloatRatingViewDelegate { +// MARK: FloatRatingViewDelegate - // MARK: FloatRatingViewDelegate +extension ViewController: FloatRatingViewDelegate { func floatRatingView(_ ratingView: FloatRatingView, isUpdating rating: Double) { - liveLabel.text = String(format: "%.2f", self.floatRatingView.rating) + self.liveLabel.text = String(format: "Live Rating: %.2f", self.floatRatingView.rating) } func floatRatingView(_ ratingView: FloatRatingView, didUpdate rating: Double) { - updatedLabel.text = String(format: "%.2f", self.floatRatingView.rating) + self.updatedLabel.text = String(format: "Updated Rating: %.2f", self.floatRatingView.rating) } - } -