Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v1.6.0 #66

Merged
merged 16 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ DerivedData
# Carthage/Checkouts

Carthage/Build
ThunderTable.framework.zip
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
language: swift
xcode_project: ThunderTable.xcodeproj # path to your xcodeproj folder
osx_image: xcode11
osx_image: xcode12
env:
global:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
include:
- xcode_scheme: ThunderTable
xcode_destination: platform=iOS Simulator,OS=13.0,name=iPhone 11 Pro Max
xcode_destination: platform=iOS Simulator,OS=14.0,name=iPhone 11 Pro Max
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class MyTableViewController: TableViewController {
}
```

# Building Binaries for Carthage

Since Xcode 12 there has been issues with building Carthage binaries caused by the inclusion of a secondary arm64 slice in the generated binary needed for Apple Silicon on macOS. This means that rather than simply using `carthage build --archive` you need to use the `./carthage-build build --archive` command which uses the script included with this repo. For more information, see the issue on Carthage's github [here](https://github.com/Carthage/Carthage/issues/3019)

We will be investigating moving over to use SPM as an agency soon, and will also look into migrating to use .xcframeworks as soon as Carthage have support for it.

# Code level documentation
Documentation is available for the entire library in AppleDoc format. This is available in the framework itself or in the [Hosted Version](http://3sidedcube.github.io/iOS-ThunderTable/)

Expand Down
24 changes: 20 additions & 4 deletions ThunderTable.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
B114F1122035CC19005D52F2 /* InputPickerViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B114F1102035CC19005D52F2 /* InputPickerViewCell.xib */; };
B11CB8CF1F320DA600E58116 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11CB8CE1F320DA600E58116 /* Extensions.swift */; };
B11CEB9F20498F0C001308B3 /* CNContact+Row.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11CEB79204977A2001308B3 /* CNContact+Row.swift */; };
B12D31092512385700274462 /* InputInlineDatePickerViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B12D31072512385700274462 /* InputInlineDatePickerViewCell.xib */; };
B12D310A2512385700274462 /* InputInlineDatePickerViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B12D31082512385700274462 /* InputInlineDatePickerViewCell.swift */; };
B14F945120444E820014F694 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14F945020444E820014F694 /* AppDelegate.swift */; };
B14F945320444E820014F694 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14F945220444E820014F694 /* ViewController.swift */; };
B14F945620444E820014F694 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B14F945420444E820014F694 /* Main.storyboard */; };
Expand Down Expand Up @@ -103,6 +105,8 @@
B114F1102035CC19005D52F2 /* InputPickerViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InputPickerViewCell.xib; sourceTree = "<group>"; };
B11CB8CE1F320DA600E58116 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
B11CEB79204977A2001308B3 /* CNContact+Row.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CNContact+Row.swift"; sourceTree = "<group>"; };
B12D31072512385700274462 /* InputInlineDatePickerViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InputInlineDatePickerViewCell.xib; sourceTree = "<group>"; };
B12D31082512385700274462 /* InputInlineDatePickerViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputInlineDatePickerViewCell.swift; sourceTree = "<group>"; };
B14F944E20444E810014F694 /* ThunderTableDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ThunderTableDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
B14F945020444E820014F694 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
B14F945220444E820014F694 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -225,6 +229,13 @@
path = Cells;
sourceTree = "<group>";
};
B12D31062512347800274462 /* Extensions */ = {
isa = PBXGroup;
children = (
);
name = Extensions;
sourceTree = "<group>";
};
B14F944F20444E810014F694 /* ThunderTableDemo */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -264,6 +275,7 @@
B17BAA341D89639100844421 /* ThunderTable */ = {
isa = PBXGroup;
children = (
B12D31062512347800274462 /* Extensions */,
B1B5C6D324FFCA8C00F05CE8 /* Scroll Offset Caching */,
B1D10CD01DA540CF003FBCB4 /* Theme.swift */,
B19C53261D8B036600B30A35 /* ApplicationLoadingIndicatorManager.swift */,
Expand Down Expand Up @@ -306,6 +318,8 @@
B19C53211D8B02F600B30A35 /* Cells */ = {
isa = PBXGroup;
children = (
B12D31082512385700274462 /* InputInlineDatePickerViewCell.swift */,
B12D31072512385700274462 /* InputInlineDatePickerViewCell.xib */,
B1C2C56D1FFCF20F00D968C5 /* InputDatePickerViewCell.swift */,
B1C2C56E1FFCF20F00D968C5 /* InputDatePickerViewCell.xib */,
B114F10F2035CC19005D52F2 /* InputPickerViewCell.swift */,
Expand Down Expand Up @@ -500,6 +514,7 @@
B108319E1F068FDF008B565D /* TableImageViewCell.xib in Resources */,
B1784D871D8C3A8A007358EA /* InputSliderViewCell.xib in Resources */,
B1EC80FF1FDE85EA00C8EE72 /* DefaultTableViewCell.xib in Resources */,
B12D31092512385700274462 /* InputInlineDatePickerViewCell.xib in Resources */,
B1C2C5701FFCF20F00D968C5 /* InputDatePickerViewCell.xib in Resources */,
B1A8983E2047117D0028CAE4 /* Value2TableViewCell.xib in Resources */,
B1AD7EC11D8BFC9D00BFCA34 /* InputTextViewCell.xib in Resources */,
Expand Down Expand Up @@ -540,6 +555,7 @@
B17BAA581D89643800844421 /* TableSection.swift in Sources */,
B1784D831D8C3A60007358EA /* InputSliderRow.swift in Sources */,
B1C2C56C1FFCEE3100D968C5 /* InputDatePickerRow.swift in Sources */,
B12D310A2512385700274462 /* InputInlineDatePickerViewCell.swift in Sources */,
B1EC81021FDE86BF00C8EE72 /* SubtitleTableViewCell.swift in Sources */,
B1B5C6D724FFCAAD00F05CE8 /* ScrollOffsetManagable.swift in Sources */,
B1B679611D89807A00B66FD8 /* TableViewCell.swift in Sources */,
Expand Down Expand Up @@ -623,7 +639,7 @@
INFOPLIST_FILE = ThunderTableDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.3sidedcube.ThunderTableDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand All @@ -646,7 +662,7 @@
INFOPLIST_FILE = ThunderTableDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.3sidedcube.ThunderTableDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -786,7 +802,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.threesidedcube.ThunderTable;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand All @@ -811,7 +827,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.threesidedcube.ThunderTable;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand Down
118 changes: 104 additions & 14 deletions ThunderTable/InputDatePickerRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,80 @@ import UIKit
/// A row which displays a date picker in the keyboard for the user
/// to select a date and formats the date nicely
open class InputDatePickerRow: InputTableRow {

/// An direct map enum to `UIDatePickerStyle` so we can provide the `preferredDatePickerStyle` on iOS
/// versions before iOS 13.4 without getting "Stored properties cannot be marked potentially unavailable with '@available'"
/// compiler warning!
public enum PickerStyle: Int {
/// Automatically pick the best style available for the current platform & mode.
case automatic = 0

/// Use the wheels (UIPickerView) style. Editing occurs inline.
case wheels = 1

/// Use a compact style for the date picker. Editing occurs in an overlay.
case compact = 2

/// Use a style for the date picker that allows editing in place.
case inline = 3

@available (iOS 13.4, *)
var datePickerStyle: UIDatePickerStyle {
switch self {
case .automatic:
return .automatic
case .compact:
return .compact
case .inline:
if #available(iOS 14.0, *) {
return .inline
} else {
return .automatic
}
case .wheels:
return .wheels
}
}

/// Returns the correct cell class for the style given the mode the date picker is set to
/// - Parameter mode: The date picker mode the date picker is in
/// - Returns: A table view cell class used to render the cell
func cellClass(for mode: UIDatePicker.Mode) -> UITableViewCell.Type {

// Even old versions of iOS can support `inline` no matter how much of a hot mess it is visually!
if self == .inline {
// Return new class
return InputInlineDatePickerViewCell.self
}

// New `inline` and `compact` date pickers are only available on iOS 14
guard #available(iOS 14, *) else {
return InputDatePickerViewCell.self
}

switch mode {
case .countDownTimer:
// countdown timer doesn't have an `inline` or `compact` representation, so we
// keep the traditional `wheels` cell for this case
return InputDatePickerViewCell.self
default:
switch self {
// Automatic, Compact and Inline should all use the inline style cell
case .automatic, .compact, .inline:
return InputInlineDatePickerViewCell.self
// All others (.wheels) should use the original date picker cell
default:
return InputDatePickerViewCell.self
}
}
}
}

/// The date picker mode for the row
open var mode: UIDatePicker.Mode = .dateAndTime

/// The preferred date picker style for the row, this will only have an effect on iOS > 13.4
open var preferredDatePickerStyle: PickerStyle = .automatic

/// The minimum date allowed by the row
open var minimumDate: Date?
Expand Down Expand Up @@ -60,32 +131,51 @@ open class InputDatePickerRow: InputTableRow {
}

open override var cellClass: UITableViewCell.Type? {
return InputDatePickerViewCell.self
return preferredDatePickerStyle.cellClass(for: mode)
}

open override func configure(cell: UITableViewCell, at indexPath: IndexPath, in tableViewController: TableViewController) {

guard let datePickerCell = cell as? InputDatePickerViewCell else { return }
guard let datePickerCell = cell as? InputDatePickerViewCell else { return }

super.configure(cell: cell, at: indexPath, in: tableViewController)

// Targets and selectors
updateTargetsAndSelectors(for: datePickerCell.textField)
// If we have a text field we use that for targets and selectors
if let textField = datePickerCell.inputTextField {
updateTargetsAndSelectors(for: textField)
// Otherwise we add them to the date picker to make sure we still get callbacks!
} else if let datePicker = datePickerCell.datePicker {
updateTargetsAndSelectors(for: datePicker)
}

datePickerCell.dateFormatter = dateFormatter
datePickerCell.textField.delegate = self
datePickerCell.datePicker.addTarget(self, action: #selector(handleChange(sender:)), for: .valueChanged)
datePickerCell.datePicker.addTarget(datePickerCell, action: #selector(InputDatePickerViewCell.updateLabel(sender:)), for: .valueChanged)
datePickerCell.inputTextField?.delegate = self
datePickerCell.datePicker?.addTarget(self, action: #selector(handleChange(sender:)), for: .valueChanged)

datePickerCell.datePicker?.addTarget(datePickerCell, action: #selector(datePickerCell.updateInputTextFieldText(sender:)), for: .valueChanged)

// Setting up date picker
datePickerCell.datePicker.minimumDate = minimumDate
datePickerCell.datePicker.maximumDate = maximumDate
datePickerCell.datePicker.datePickerMode = mode
datePickerCell.datePicker?.minimumDate = minimumDate
datePickerCell.datePicker?.maximumDate = maximumDate
datePickerCell.datePicker?.datePickerMode = mode

if #available(iOS 13.4, *) {
datePickerCell.datePicker?.preferredDatePickerStyle = preferredDatePickerStyle.datePickerStyle
}

if let dateValue = value as? Date {
datePickerCell.textField.text = dateFormatter.string(from: dateValue)
} else {
datePickerCell.textField.text = nil
}
if let textField = datePickerCell.inputTextField {

if let dateValue = value as? Date {
textField.text = dateFormatter.string(from: dateValue)
} else {
textField.text = nil
}

} else {

datePickerCell.datePicker?.date = value as? Date ?? Date()
}
}

@objc private func handleChange(sender: UIDatePicker) {
Expand Down
41 changes: 26 additions & 15 deletions ThunderTable/InputDatePickerViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,31 @@

import UIKit

/// A `TableViewCell` subclass with an image, title label, and a text field aligned horizontally
///
/// This cell subclass allows the user to pick a date using a `UIDatePicker`set as the text field's
/// `inputView`, meaning it shows in-place of the default iOS keyboard
open class InputDatePickerViewCell: TableViewCell {

@IBOutlet weak public var textField: UITextField!

public var datePicker = UIDatePicker()

internal var dateFormatter: DateFormatter = DateFormatter()

public var inputTextField: UITextField? {
return textField
}

/// The text field allowing the user to enter a date
@IBOutlet weak public var textField: UITextField?

/// The date picker the user uses to pick the date
@IBOutlet public var datePicker: UIDatePicker? = UIDatePicker()

/// The date formatter used to format the date displayed in `textField`
public var dateFormatter: DateFormatter? = DateFormatter()

override open func becomeFirstResponder() -> Bool {
return textField.becomeFirstResponder()
return textField?.becomeFirstResponder() ?? false
}

override open func resignFirstResponder() -> Bool {
return textField.resignFirstResponder()
return textField?.resignFirstResponder() ?? false
}

open override func awakeFromNib() {
Expand All @@ -38,15 +49,15 @@ open class InputDatePickerViewCell: TableViewCell {
UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDone(sender:)))
]

textField.inputView = datePicker
textField.inputAccessoryView = doneToolbar
textField?.inputView = datePicker
textField?.inputAccessoryView = doneToolbar
}

@objc private func handleDone(sender: UIBarButtonItem) {
textField.resignFirstResponder()
}

@objc func updateLabel(sender: UIDatePicker) {
textField.text = dateFormatter.string(from: sender.date)
textField?.resignFirstResponder()
}

@objc public func updateInputTextFieldText(sender: UIDatePicker) {
textField?.text = dateFormatter?.string(from: sender.date)
}
}
24 changes: 24 additions & 0 deletions ThunderTable/InputInlineDatePickerViewCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// InputInlineDatePickerViewCell.swift
// ThunderTable
//
// Created by Simon Mitchell on 16/09/2020.
// Copyright © 2020 3SidedCube. All rights reserved.
//

import UIKit

/// An `InputDatePickerViewCell` subclass with an image, title label, and a date picker aligned horizontally
///
/// This cell subclass allows the user to pick a date using a `UIDatePicker` embedded "inline"
/// as one of the cell's subviews. This allows for use of
open class InputInlineDatePickerViewCell: InputDatePickerViewCell {

override open func becomeFirstResponder() -> Bool {
return datePicker?.becomeFirstResponder() ?? false
}

override open func resignFirstResponder() -> Bool {
return datePicker?.resignFirstResponder() ?? false
}
}